SlopCop

This is a synthetic example of a finished scan. The repository, its code and its findings are made up, not taken from a real scan.

example/acme-service

4 confirmed findings to fix.

Commit 7b4e2a1
Findings
4
Files
4
Severity
  • Critical 1
  • Error 2
  • Warning 1

Fix first

The worst 3 of 4 confirmed findings, with the evidence and the fix.

All 4 findings

Login skips the password check

src/auth/login.tsLine 22
export async function login(username: string, password: string): Promise<Session> {  await rateLimit.check(`login:${username}`, MAX_ATTEMPTS);  const valid = await verifyCredentials(username, password);  audit.record("login-attempt", { username });  return database.createSession(username);···
Problem

login stores the result of verifyCredentials in valid but never reads it, so database.createSession runs whether or not the password matched.

Impact

Unless a caller checks the password again, a wrong password still returns a working session for that username.

Recommended solution

Throw an authentication error when valid is false, before the session is created, and add a test that a wrong password creates no session.

Why this was flagged
Check

Dead code and unused abstractions matched src/auth/login.ts:22.

Source read for this finding
  • src/auth/login.ts:18-30
Independent review

Kept with high confidence. The verifyCredentials result is assigned and never read before the session is created.

Dry run deletes the account

src/accounts/delete-account.tsLines 16–17
export async function deleteAccount(accountId: string, { dryRun = false } = {}) {  const account = await database.getAccount(accountId);  if (dryRun) logger.info(`Would delete account ${account.id}`);  await database.deleteAccount(account.id);  await audit.record("account-deleted", { accountId });}
Problem

When dryRun is true, deleteAccount logs the preview and carries on to database.deleteAccount, because the dry-run branch never returns.

Impact

A dry run deletes the account it was meant to preview, and the audit log records the deletion as real.

Recommended solution

Return straight after logging the preview, or move the deletion into an explicit else branch, and add a test that a dry run leaves the account in place.

Why this was flagged
Check findings at these lines

No check finding in this report is at these lines. This finding comes from the AI review reading the source below.

Source the review cited
  • src/accounts/delete-account.ts:14-19
Independent review

Kept with high confidence. The dry-run branch logs the preview and falls through to the delete call.

Limits
  • The AI review reads selected excerpts of the repository, not every file. This finding is a reviewed judgement about the lines above, not a deterministic match.
  • This finding has no identity that carries across scans, so it can’t be suppressed on its own.

Refund amount isn’t checked

The refund amount crosses three files unchecked

The refund amount crosses three files unchecked. 3 reviewed components and 2 reviewed relationships. Route reads the amount from the request body (src/routes/refunds.ts:14–17) leads to refundOrder passes it on without a limit (src/orders/refund-order.ts:9–14): Number(req.body.amount) (src/routes/refunds.ts:15). refundOrder passes it on without a limit (src/orders/refund-order.ts:9–14) leads to Payments client sends it to the gateway (src/payments/client.ts:21–23): Same amount, never compared with the order (src/orders/refund-order.ts:11).

Directed evidence graphSame amount, nevercompared with the orderNumber(req.body.amount)refundOrder passes iton without a limitrefund-order.ts:9–14Payments client sendsit to the gatewayclient.ts:21–23Route reads the amountfrom the request bodyrefunds.ts:14–17
Source evidence
  • Finding: src/orders/refund-order.ts:9–14Finding sourcesrc/orders/refund-order.ts:9–14
  • Component: Route reads the amount from the request bodySourcesrc/routes/refunds.ts:14–17
  • Component: refundOrder passes it on without a limitSourcesrc/orders/refund-order.ts:9–14
  • Component: Payments client sends it to the gatewaySourcesrc/payments/client.ts:21–23
  • Relationship: Route reads the amount from the request body → refundOrder passes it on without a limitRelationship sourcesrc/routes/refunds.ts:15
  • Relationship: refundOrder passes it on without a limit → Payments client sends it to the gatewayRelationship sourcesrc/orders/refund-order.ts:11
Source 1 of 3
src/orders/refund-order.tsLines 9–14
export async function refundOrder(orderId: string, amount: number) {  const order = await database.orders.get(orderId);  const refund = await payments.refund(order.chargeId, amount);  await database.orders.markRefunded(orderId, refund.id);  return refund;}
Text alternative
Reviewed components
  1. Route reads the amount from the request bodySourcesrc/routes/refunds.ts:14–17
  2. refundOrder passes it on without a limitSourcesrc/orders/refund-order.ts:9–14
  3. Payments client sends it to the gatewaySourcesrc/payments/client.ts:21–23
Reviewed relationships
  1. Route reads the amount from the request bodyrefundOrder passes it on without a limit
    Number(req.body.amount)Relationship sourcesrc/routes/refunds.ts:15
  2. refundOrder passes it on without a limitPayments client sends it to the gateway
    Same amount, never compared with the orderRelationship sourcesrc/orders/refund-order.ts:11
Problem

The refund route reads amount from the request body and refundOrder passes it to payments.refund without comparing it with what the order was paid. The payments client sends it to the gateway as it is.

Impact

A staff request can refund more than the order's total, and a missing amount reaches the gateway as NaN.

Recommended solution

Check the amount in refundOrder: reject anything that isn't a positive number or that exceeds the order's total less earlier refunds, and add a test for each case.

Why this was flagged
Check findings at these lines

No check finding in this report is at these lines. This finding comes from the AI review reading the source below.

Source the review cited
  • src/orders/refund-order.ts:9-14
  • src/routes/refunds.ts:14-17
  • src/payments/client.ts:21-23
Independent review

Kept with high confidence. The amount from the request body reaches the payment gateway with no bound in any of the three files.

Limits
  • The AI review reads selected excerpts of the repository, not every file. This finding is a reviewed judgement about the lines above, not a deterministic match.
  • This finding has no identity that carries across scans, so it can’t be suppressed on its own.

Findings

Every confirmed finding, grouped by the check or AI review that raised it. Open a group to read its findings here.

Possible credentials

The secret scan matched these lines by pattern. They are not reviewed by AI. SlopCop doesn’t read or show the value.

If one is a real credential, rotate it and remove it from the code.

  • src/payments/client.ts:4Matches API key · high confidence

Design review

Design recommendations from AI review, with the code and relationships behind each suggestion. 1 more problem it found was confirmed as a defect and is under Findings.

Full design review.

Invoice export checks session expiry with its own rule

Two places decide when a session expires

Two places decide when a session expires. 3 reviewed components and 2 reviewed relationships. Export route reads the session cookie (src/routes/billing.ts:22–25) leads to Export handler checks idle time itself (src/billing/export-invoices.ts:27–29): Passes a raw session id (src/routes/billing.ts:23). Export handler checks idle time itself (src/billing/export-invoices.ts:27–29) leads to Auth defines expiry and revocation (src/auth/sessions.ts:13–18): Uses 30 minutes and skips revocation (src/billing/export-invoices.ts:29).

Directed evidence graphUses 30 minutes andskips revocationPasses a raw session idAuth defines expiryand revocationsessions.ts:13–18Export handler checksidle time itselfexport-invoices.ts:27–29Export route reads thesession cookiebilling.ts:22–25
Source evidence
  • Finding: src/billing/export-invoices.ts:27–29Finding sourcesrc/billing/export-invoices.ts:27–29
  • Component: Export route reads the session cookieSourcesrc/routes/billing.ts:22–25
  • Component: Export handler checks idle time itselfSourcesrc/billing/export-invoices.ts:27–29
  • Component: Auth defines expiry and revocationSourcesrc/auth/sessions.ts:13–18
  • Relationship: Export route reads the session cookie → Export handler checks idle time itselfRelationship sourcesrc/routes/billing.ts:23
  • Relationship: Export handler checks idle time itself → Auth defines expiry and revocationRelationship sourcesrc/billing/export-invoices.ts:29
Source 1 of 3
src/billing/export-invoices.tsLines 27–29
  const session = await database.sessions.find(request.sessionId);  const idleMinutes = (Date.now() - session.lastSeenAt.getTime()) / 60_000;  if (idleMinutes > 30) throw new UnauthorizedError("Session expired");
Text alternative
Reviewed components
  1. Export route reads the session cookieSourcesrc/routes/billing.ts:22–25
  2. Export handler checks idle time itselfSourcesrc/billing/export-invoices.ts:27–29
  3. Auth defines expiry and revocationSourcesrc/auth/sessions.ts:13–18
Reviewed relationships
  1. Export route reads the session cookieExport handler checks idle time itself
    Passes a raw session idRelationship sourcesrc/routes/billing.ts:23
  2. Export handler checks idle time itselfAuth defines expiry and revocation
    Uses 30 minutes and skips revocationRelationship sourcesrc/billing/export-invoices.ts:29
Problem

The export route passes the raw session id to the export handler, which reads the session row and applies its own 30-minute idle limit with no revocation check, instead of calling isSessionActive.

Impact

A revoked session, or one idle for 20 to 30 minutes, can still export invoices after the rest of the service has signed it out.

Recommended solution

Check the session with isSessionActive before exporting, and keep the expiry rule, timeout included, in the auth module.

Why this was flagged
Check findings at these lines

No check finding in this report is at these lines. This finding comes from the AI review reading the source below.

Source the review cited
  • src/billing/export-invoices.ts:27-29
  • src/routes/billing.ts:22-25
  • src/auth/sessions.ts:13-18
Independent review

Kept with high confidence. The export handler re-implements idle expiry and skips the revocation check.

Limits
  • The AI review reads selected excerpts of the repository, not every file. This finding is a reviewed judgement about the lines above, not a deterministic match.
  • This finding has no identity that carries across scans, so it can’t be suppressed on its own.

See what turns up
in your own code.

Create an account, pick a repository, and SlopCop starts indexing it.

Set it up with us.

Leave your email and we’ll arrange a call about running SlopCop in your team’s coding agents and CI, or anything else you’d like to know.

We’ll use your email to respond. No scan or report is needed.