Security report: Full

Independent check of a web app

shop.example https://shop.example/

Date
2026-11-07
Report ID
5a3b1e00-0000-4000-8000-000000000000
Version
1
SHA-256
fb9ff4c2ff530d7b8b05f4622d7e389ab732e25f51676dc2cd21e1f34878fee5

Prepared by yof (yof.io)

Sample: made-up site. This is a sample report for shop.example, a site that does not exist. Every finding in it is made up.

Confidential: prepared for the owner of shop.example

This is a translation of signed yof report 5a3b1e00-0000-4000-8000-000000000000. The signed original is in English; its SHA-256 is below. Technical details (fixes, steps, references) are in English.

Scan the QR code or open https://yof.io/verify/5a3b1e00-0000-4000-8000-000000000000. The page checks yof's signature and shows only what the report's owner chose to share.

What this report is and isn't

This report is a check of shop.example at one point in time, as of 2026-11-07. It covers the repository, the dependencies and the live addresses named in its scope section, and nothing else.

It was made by automated rules and tests. Depending on the scope, yof read the code, checked the packages, tested the live site and, with the owner's consent, ran attack tests. The scope section lists exactly what was done and what was not.

It is evidence to support your security and compliance work. It is not a certification, a conformity assessment or legal advice, and it does not assess governance, policies, processes or other duties that are not technical.

A result with no findings does not mean the app has no vulnerabilities. Automated checks cannot find every flaw. Weaknesses nobody knows about yet (zero-days), flaws in business logic and anything outside the scope may remain, and the app may change after the date shown.

As far as the law allows, yof's liability for this report is limited to the price paid for it. Consumer law where you live may not allow some of these limits; where it does not, they do not apply to you.

Document control

Version history
Version 1, issued 2026-11-07
Requested by
The owner of shop.example, through the yof app (order 00000000).
Distribution
Confidential. Prepared for the owner of shop.example, who may share it with the people who need it, such as auditors, insurers or customers. Anyone holding a copy can check it with the QR code.
Algorithm
none (sample, not signed) (yof-report/v1 sample)
Fingerprint (SHA-256)
fb9ff4c2ff530d7b8b05f4622d7e389ab732e25f51676dc2cd21e1f34878fee5

Summary

High: at least one problem should be fixed now.

Scope

Coverage: 45% of the parts yof can examine.

Not tested

What was checked and what was not

This states the reach of this report. A part that was not checked is not assumed to be fine.

Checked

Not checked, and why

Never covered by automated checks

How sure yof is of each finding

Every finding carries one verdict. Only confirmed findings and findings that need validation are counted. Hardening notes and rejected findings are listed apart and never counted.

What each severity means

Findings (5)

Open findings only, by verdict: confirmed (4), needs validation (0). Listed separately: hardening notes (1), rejected (0).

Fix now · Open

F-001 A package your app installs has a known serious vulnerability

Verdict: Confirmed. Severity: High. Why: The repository holds the exact evidence. yof did not see it on the live app, so it is rated high at most.

The weakness is public, with a published fix. Attackers scan for apps that still run the old version.

Where: package-lock.json:812 (example-shop/storefront at 0f1e2d3c4b5a)

Steps to see it:

  1. Open package-lock.json:812 (example-shop/storefront at 0f1e2d3c4b5a).
  2. Expected instead: The installed version of minimist is at or above 1.2.6.

Business impact: A published weakness in a component could be used against the app.

Package
minimist (npm)
Installed version
1.2.5
Advisories
GHSA-xvch-5gv4-984h https://github.com/advisories/GHSA-xvch-5gv4-984h, CVE-2021-44906 https://nvd.nist.gov/vuln/detail/CVE-2021-44906
First fixed version
1.2.6
Lockfile
package-lock.json:812
Named in
package.json

Fix: Upgrade minimist from 1.2.5 to 1.2.6 or newer (advisories: GHSA-xvch-5gv4-984h, CVE-2021-44906). Update package-lock.json with your package manager rather than by hand, run the install and the tests, and check whether the upgrade needs code changes.

References:

  • GHSA-xvch-5gv4-984h (https://github.com/advisories/GHSA-xvch-5gv4-984h)
  • CVE-2021-44906 (https://nvd.nist.gov/vuln/detail/CVE-2021-44906)
  • CWE-1395: Dependency on Vulnerable Third-Party Component (https://cwe.mitre.org/data/definitions/1395.html)
  • OWASP A06:2021: Vulnerable and Outdated Components

First seen: 2026-10-30

Fix now · Open

F-002 Your Stripe secret key is in your page code

Verdict: Confirmed. Severity: Critical. Why: yof saw it on the live app.

Anyone can use it to take payments, give refunds and read your customers' payment details.

Where: https://shop.example/assets/app.js

Evidence (masked): sk_live_****9f2a

Steps to see it:

  1. Open https://shop.example/assets/app.js without signing in.
  2. What yof saw (masked): sk_live_****9f2a
  3. Expected instead: No live Stripe secret key appears in code that visitors can download.

Business impact: Someone could sign in as another person or keep a session they should not have.

Fix: Remove the Stripe secret key (it starts with sk_live_) from all browser code and from any environment variable the browser can read. Create payments on the server only (an API route, server action or Supabase Edge Function) and send the browser just the client secret of the payment. The browser should only ever see the publishable key (pk_live_). Never paste the real key into this chat, never print it, and do not invent a replacement key. Tell me when the code no longer contains it, so I can create a new key in the provider's dashboard and delete the old one (the old one has been public, so it must be replaced).

References:

  • CWE-798: Use of Hard-coded Credentials (https://cwe.mitre.org/data/definitions/798.html)
  • OWASP A07:2021: Identification and Authentication Failures

First seen: 2026-10-30

Fix now · Open

F-003 Anyone can read a table in your database

Verdict: Confirmed. Severity: High. Why: yof saw it on the live app.

A stranger can download the rows in this table, such as your customers' names, emails or orders, without signing in.

Where: https://shop.example/

Evidence (masked): table orders: 3 rows readable without signing in

Steps to see it:

  1. Open https://shop.example/ without signing in.
  2. What yof saw (masked): table orders: 3 rows readable without signing in
  3. Expected instead: Visitors who are not signed in cannot read this table.

Business impact: People could see or change data that belongs to someone else.

Fix: A Supabase table can be read by anyone with the public anon key. Turn on Row Level Security for this table (and every other table), then add policies so a signed-in person can only read their own rows (for example using auth.uid() = user_id). Remove any policy that allows the anon role to select everything. Write the SQL for me and explain what each policy allows. Never paste real customer data or keys into this chat.

-- for each table the browser can reach
alter table public.your_table enable row level security;
create policy "own rows" on public.your_table
  for select using (auth.uid() = user_id);

References:

  • CWE-862: Missing Authorization (https://cwe.mitre.org/data/definitions/862.html)
  • OWASP A01:2021: Broken Access Control

First seen: 2026-10-30

Fix now · Open

F-004 One user can read another user's records by changing the id

Verdict: Confirmed. Severity: High. Why: yof saw it on the live app.

A test account opened a record of your other test account just by using its id, so real users can read each other's data.

Where: GET /api/orders/{id} (as user b)

Evidence (masked): 200 with another customer's order

Steps to see it:

  1. Sign in as test user b.
  2. Send GET /api/orders/{id} with an id that belongs to another user or role.
  3. What yof saw (masked): 200 with another customer's order
  4. Expected instead: An account can open only its own records; another account's id answers 404 or 403.

Business impact: People could see or change data that belongs to someone else.

Fix: In my app, user B can read a record that belongs to user A by putting A's record id in the address (or sees it in a list). On the server, every query for a record or a list must be filtered by the signed-in user (or their workspace), for example `where id = :id and owner_id = :currentUser`, and answer 404 when the record is not theirs. If the database supports row-level security, turn it on with a policy that only allows the owner. Do not rely on ids being hard to guess.

References:

  • CWE-639: Authorization Bypass Through User-Controlled Key (https://cwe.mitre.org/data/definitions/639.html)
  • OWASP A01:2021: Broken Access Control
  • OWASP API1:2023: Broken Object Level Authorization

First seen: 2026-10-30

Fix this week · Fixed

F-005 Your domain has no rule for fake email

Verdict: Needs validation. Severity: Medium. Why: The check did not keep the evidence needed to confirm it.

Mail providers don't know what to do with messages that pretend to be you, so many of them get delivered.

Where: https://shop.example/

Steps to see it:

  1. Look up the domain's DNS TXT records (for example: dig TXT shop.example).
  2. Expected instead: The domain publishes a DMARC policy of quarantine or reject.

Business impact: A setting leaves an opening that is easy to find.

Fix: The domain has no DMARC record. Add a TXT record whose name (host) is exactly _dmarc, not @ (a DMARC record at the root is ignored), starting with monitoring: v=DMARC1; p=none; rua=mailto:<an address you read>. After a few weeks of clean reports, move to p=quarantine and then p=reject.

_dmarc.shop.example.  TXT  "v=DMARC1; p=quarantine; rua=mailto:dmarc@shop.example"

References:

  • CWE-290: Authentication Bypass by Spoofing (https://cwe.mitre.org/data/definitions/290.html)
  • OWASP A05:2021: Security Misconfiguration

First seen: 2026-10-30

Hardening notes (not counted as findings)

Good practice that would add a layer of protection. yof demonstrated no risk, so these are not findings and are in no count.

Accepted risks and why

The owner looked at these findings and decided to accept the risk, for the reason given. They are not counted as open, and they are listed here so nothing is hidden.

H-002 No rule limits which scripts can run

Where
https://shop.example/
Reason
The payment widget needs inline scripts until its next version; we review this in January.
Accepted by
owner@shop.example
Accepted on
2026-11-05
Accepted in
the yof app

A Stripe test secret key is in your page code

Where
tests/fixtures/payments.ts
Reason
A Stripe test key in a test fixture; it cannot take real payments.
Accepted by
Sam (developer)
Accepted on
2026-11-02
Accepted in
the repository (.yof/accepted.json)

Glossary

Finding
Something yof saw that could let an attacker in or expose data, with where it is and how to see it.
Urgency
yof's plain order of work: fix now, fix this week, nice to have, for information.
CVSS 4.0
The common scoring system for how serious a weakness is, from 0 to 10, with the vector that explains the score.
CWE
The common list of weakness types; each finding names the type it belongs to.
Coverage
How much of the six parts yof can examine were tested in this report.
Accepted risk
A finding the owner decided to keep, with a reason. It is listed, not counted as open.
SBOM
Software bill of materials: the list of packages the app is built from.
Fingerprint
The SHA-256 hash of the report's content. Any change to the report changes it.

How to verify

  1. Scan the QR code on the cover, or open the address printed under it. The page checks yof's signature against the register.
  2. To check a file you were sent, choose it on that page: your browser works out its SHA-256 and compares it, the file is not uploaded.
  3. With an Ed25519 signature, anyone can also check it offline with yof's public key, over the report ID, version, issue date and content hash.

Scan the QR code or open https://yof.io/verify/5a3b1e00-0000-4000-8000-000000000000. The page checks yof's signature and shows only what the report's owner chose to share.

Limits