Sample report — fictional project, findings written for illustration.

acme-agency/storefront

codewebcompletedhttps://staging.example.com

This is the shape of what lands in your account after a scan: a score and a grade, every finding with the file and line it comes from, why it matters and how to fix it, then an AI reasoning pass that connects the findings to each other.

D

46/100

1

Critical

2

High

2

Medium

1

Low

1

Info

Each finding deducts points from 100: 25 for Critical, 10 for High, 4 for Medium, 1 for Low, 0 for Info. 90 and above is an A, 75 to 89 a B, 60 to 74 a C, 40 to 59 a D, below 40 an F.

gitleaksosv-scannerweb-scannerheader-check

Critical

1

Hard-coded payment API secret

A live-looking payment provider secret is committed in a configuration file and present in the repository history.

config/payments.ts:12

A02:2021 — Cryptographic Failures
export const paymentsConfig = {
  merchantId: "acme-storefront",
  apiSecret: "sample-secret-do-not-use-0000", // illustrative value
};

Why it matters. Anyone who can read the repository, a fork, or a leaked build artifact can act as the shop against the payment provider: issue refunds, read orders, create charges.

Suggested fix. Rotate the secret now, remove it from the history, and load it from the environment (process.env.PAYMENTS_API_SECRET) or a secrets manager. Add a pre-commit secret scan.

gitleaks

High

2

Insecure direct object reference on order lookup

GET /api/orders/:id returns any order to any signed-in customer; ownership is never compared with the session.

src/routes/orders.ts:48

A01:2021 — Broken Access Control
router.get("/api/orders/:id", requireLogin, async (req, res) => {
  const order = await db.orders.findById(req.params.id);
  res.json(order); // no check that order.customerId === req.user.id
});

Why it matters. Order ids are sequential, so one customer can walk the whole range and read every other customer's name, address and purchases.

Suggested fix. Scope the query to the caller: findOne({ id, customerId: req.user.id }) and return 404 when nothing matches. Prefer non-guessable ids.

web-scanner

Vulnerable dependency: example-templating 2.3.1

CVE-2099-00001 (illustrative id): server-side template injection in versions below 2.4.0, reachable from the order-confirmation e-mail renderer.

package-lock.json:2187

A06:2021 — Vulnerable and Outdated ComponentsCVE-2099-00001 (illustrative)
"node_modules/example-templating": {
  "version": "2.3.1",   // fixed in 2.4.0
  "resolved": "https://registry.example.com/example-templating/-/example-templating-2.3.1.tgz"
}

Why it matters. The renderer receives the customer's display name. A crafted name executes template expressions on the server when the e-mail is built.

Suggested fix. Upgrade to example-templating 2.4.0 or later, rebuild the lockfile, and confirm the resolved version after install.

osv-scanner

Medium

2

Open redirect after login

The `next` parameter is followed without checking that it is a relative path on this site.

src/routes/login.ts:73

A01:2021 — Broken Access Control
res.redirect(req.query.next ?? "/account");
// https://staging.example.com/login?next=https://evil.example.net

Why it matters. A link on the real login page can send customers to a look-alike site right after they typed their password, which makes phishing far more convincing.

Suggested fix. Accept only paths that start with a single `/`, or map `next` to an allow-list of known destinations.

web-scanner

Missing security headers

https://staging.example.com answers without Content-Security-Policy, X-Content-Type-Options or a Strict-Transport-Security max-age.

https://staging.example.com/

A05:2021 — Security Misconfiguration
HTTP/2 200
content-type: text/html; charset=utf-8
server: example-edge
# no content-security-policy
# no x-content-type-options
# no strict-transport-security

Why it matters. Without a CSP a single injected script runs with full page privileges; without HSTS a first visit over plain HTTP can be intercepted.

Suggested fix. Send `Content-Security-Policy` with a nonce-based script-src, `X-Content-Type-Options: nosniff`, and `Strict-Transport-Security: max-age=31536000; includeSubDomains`.

header-check

Low

1

Session cookie without SameSite

The session cookie sets Secure and HttpOnly but no SameSite attribute.

src/middleware/session.ts:31

A05:2021 — Security Misconfiguration
cookie: { httpOnly: true, secure: true } // sameSite not set

Why it matters. Browsers default differ; an explicit value keeps cross-site requests from carrying the session where they should not.

Suggested fix. Set `sameSite: "lax"` (or "strict" if no cross-site entry point needs the session).

web-scanner

Info

1

Server version banner disclosed

The `X-Powered-By` header names the framework and its major version.

https://staging.example.com/

x-powered-by: Express

Why it matters. Not exploitable on its own; it saves an attacker a step when picking which known issue to try.

Suggested fix. Disable the header (app.disable("x-powered-by")).

header-check
Add-on

AI reasoning panel

After the deterministic scanners finish, several AI models reason over their findings together and a judge consolidates the result. The pass is read-only: it works from the findings above and sends no new request to the site.

Exploit chain

Leaked secret + order IDOR: from repository access to every customer's orders

  1. The payment secret in config/payments.ts:12 (F-1) lets a reader of the repository call the provider as the shop.
  2. The provider returns customer references and order ids, which feed the sequential lookup in src/routes/orders.ts:48 (F-2).
  3. Together they turn read access to one repository into read access to the whole order book, with no account on the site at all.

Fixing either link breaks the chain; fixing F-1 first also closes the path from outside the site.

Business-logic observation

Discount code is checked when the cart is displayed, not when the order is placed

The code that applies the discount runs in the cart view, and the checkout handler appears to trust the total it receives. If that holds, a customer could keep a discount after the code has expired. No scanner can see this from a response alone, so it is flagged for your consented verification rather than reported as a finding.

How the panel reports. Verdicts are PASS, CAUTION or FAIL. A PASS is the strongest claim a report can make, so it is withheld, and the score capped, when coverage was thin, when no finding was backed by an actual execution, or when a finding cites a location that does not resolve in the code supplied. How to read a report

Smart-contract verification excerpt

For contracts, a finding is not left as an opinion: it is replayed on a local fork of the target chain. This excerpt is from a fictional contract, AcmeVault.sol.

Verdict: FAILbacked by an execution on a local fork

Reentrancy in withdraw() lets a caller drain the vault

contracts/AcmeVault.sol:64

function withdraw(uint256 amount) external {
    require(balances[msg.sender] >= amount, "insufficient");
    (bool ok, ) = msg.sender.call{value: amount}(""); // external call first
    require(ok, "send failed");
    balances[msg.sender] -= amount;                    // state updated after
}
$ forge test --fork-url $LOCAL_FORK --match-test test_reentrancyDrain -vv
[PASS] test_reentrancyDrain()
  vault balance before : 100.0 ETH
  attacker deposit     :   1.0 ETH
  vault balance after  :   0.0 ETH   (illustrative output)

Suggested fix. Update the balance before the external call (checks-effects-interactions) or guard the function with a reentrancy lock.

Your first AI reasoning pass is free

Create an account, run a scan of your own project, and spend your free run on a reasoning pass.