Every push gets a lightweight security pass.
Faultmark listens for GitHub push events, reviews only what changed, pulls in repo memory, then sends a concise summary to your inbox. When there’s a real finding, it opens an audit PR automatically.
Faultmark Automated Security Audit
3 issues found. Review each finding below and apply fixes before merging.
This PR was automatically opened by Faultmark in response to a direct push. No code has been modified in this branch. This is a read-only audit report.
| Commit scanned | a4d7e2c |
| Branch | main |
| Overall scan confidence | ████████░░ 82% (High) |
| Issues found | 3 |
| Severity | Count |
|---|---|
| Critical | 2 |
| High | 1 |
| Total | 3 |
| Severity | [CRITICAL] |
| Type | Injection Attack |
| File | lib/db/search.ts · L34–L41 |
| Per-finding confidence | █████████░ 91% |
| Validation status | Validated — no contradicting evidence found |
`searchTerm` from `req.query` is interpolated directly into the SQL string without parameterization. An attacker can craft a value like `' OR 1=1 --` to bypass filters and read arbitrary rows.
const rows = await db.query(
`SELECT * FROM users WHERE name = '${searchTerm}'`
)const rows = await db.query( 'SELECT * FROM users WHERE name = $1', [searchTerm] )
Why this fix works: Parameterized queries separate SQL structure from data, making injection impossible regardless of input content.
| Severity | [CRITICAL] |
| Type | Auth Bypass |
| File | app/api/admin/users/[id]/route.ts · L12–L28 |
| Per-finding confidence | █████████░ 88% |
| Validation status | Validated — no contradicting evidence found |
The `DELETE` handler calls `db.deleteUser(id)` before verifying the session has admin role. Any authenticated user can delete any account by calling this endpoint directly.
export async function DELETE(req, { params }) {
const session = await getSession(req)
if (!session) return unauthorized()
await db.deleteUser(params.id)
return ok()
}export async function DELETE(req, { params }) {
const session = await getSession(req)
if (!session || session.user.role !== 'admin')
return unauthorized()
await db.deleteUser(params.id)
return ok()
}Why this fix works: Role check must happen before any destructive operation. Checking authentication alone is insufficient.
| Severity | [HIGH] |
| Type | Logic Error |
| File | lib/billing/convert.ts · L88–L96 |
| Per-finding confidence | ████████░░ 76% |
| Validation status | Partially validated — some conflicting signals present |
`Math.round()` is applied before multiplying by the exchange rate, discarding fractional cents. For large transactions this can produce totals that are off by up to ±5 cents, affecting reconciliation and potentially overcharging customers.
const cents = Math.round(amount) * exchangeRate
const cents = Math.round(amount * exchangeRate)
Why this fix works: Rounding should occur after all arithmetic to minimise precision loss. Apply it as the last operation before storing or charging.