---
name: vibe-check-scan-interpret
version: 1.0.0
---

# Vibe Check Scan — Result Interpretation Guide

Fetch this document once per conversation when you need to explain findings in depth or answer remediation questions. Do not fetch it on every call.

## Module scores and weights

| Module | Weight | What drives the score down |
|--------|--------|---------------------------|
| headers | 26.25% | Missing CSP, HSTS, and X-Content-Type-Options hurt most. Missing X-Frame-Options or Permissions-Policy is usually a lighter hardening gap unless the app handles sensitive user actions. |
| tls | 22.5% | Weak protocol (TLS 1.0/1.1), expiring certificate, untrusted chain, weak ciphers. |
| cors | 15% | Wildcard origin, credentials with wildcard, localhost or null origin allowed. |
| apiSurface | 11.25% | Confirmed exposures only — publicly readable sensitive files, leaked server-secret material, unprotected business-data endpoints, accessible source maps. |
| cve | 25% (confirmed matches only) | React Server Components detected plus an exact React version that OSV.dev reports advisories for (status confirmed_vulnerable) scores 0 and blocks an A. Status uncertain (version unresolved or OSV unreachable) and not_vulnerable do not affect the grade — check the affectsGrade flag. |

Headers and TLS account for most of the grade; a confirmed RSC advisory match and server-secret material in client JavaScript are the things to fix first.

## APISurface finding categories

Every `APISurfaceFinding` has a `category` field. Only `confirmedExposure` findings reduce the score.

### confirmedExposure — counts against score

| reason | Plain-English meaning | Typical example |
|--------|-----------------------|-----------------|
| `public_sensitive_file` | A file like `.env`, `.git/config`, or `backup.sql` returned readable content | `/.env → 200` with key=value pairs |
| `public_client_secret` | Server-secret material was found in same-origin JavaScript. Evidence is redacted and validity was not tested. | `/app.js` with `stripe_live …4x9Q` |
| `public_source_map` | A `.js.map` file is publicly downloadable, exposing original source code | `/main.js.map → 200` |
| `unauthenticated_business_data` | An API endpoint returned records, emails, tokens, or other data without requiring auth | `/api/users → 200` with user array |
| `redirect_to_readable_content` | A redirect chain led to readable sensitive content on the same origin | `/.env → 301 → /.env.bak → 200` |

### needsReview — does not affect score, review before acting

| reason | Plain-English meaning | Typical example |
|--------|-----------------------|-----------------|
| `public_credential_identifier` | A credential identifier, such as an AWS access-key ID without the secret access key, appeared in same-origin JavaScript. This does not prove a usable credential. | `/app.js` with `aws_access_key …ABCD` |

### protectedSurface — does not affect score, informational

| reason | Plain-English meaning | Typical example |
|--------|-----------------------|-----------------|
| `auth_protected_endpoint` | An API endpoint requires authentication — correctly secured | `/api/users → 401` |
| `blocked_sensitive_probe` | A sensitive file path is blocked at the server or edge — correctly secured | `/.env → 403` |

These are good signals. No action required unless the path should not exist at all.

### expectedPublicEndpoint — does not affect score

| reason | Plain-English meaning | Typical example |
|--------|-----------------------|-----------------|
| `public_discovery_endpoint` | A health, status, or API index path — intentionally public | `/api/health → 200` |
| `non_sensitive_metadata` | A JSON endpoint returned only metadata (version, uptime, links) | `/api → 200 {"version":"1.0"}` |

No action required.

### hardeningOpportunity — informational, small or no score deduction

| reason | Plain-English meaning | Typical example |
|--------|-----------------------|-----------------|
| `blocked_source_map` | Source maps exist in the build but are blocked at the edge — good, but eliminating them from the build entirely would be better | `/main.js.map → 403` with sourceMappingURL hint in HTML |
| `public_client_config` | Public browser config, such as Supabase anon config, Firebase config, or Google Maps browser keys. This is not a server secret by itself. | `/app.js` with `firebase_config …ABCD` |

## Remediation by module

### Security headers (26.25% weight)

Each finding carries an `assessment`: `effective` (the stated check passed — not a security guarantee), `weak` (recognised but materially reduced protection, e.g. a CSP with `'unsafe-inline'` and no nonce, or report-only), `missing` (absent — a hardening opportunity, not a confirmed vulnerability), `invalid` (present but self-defeating), `unknown` (semantics unsupported — excluded from the score) or `not_applicable` (e.g. HSTS on a non-HTTPS response — excluded). The score denominator (`maxScore`) only counts applicable, supported, grade-eligible checks. A module made up entirely of `missing` findings is "needs hardening", not a failure.

CSP and HSTS carry the most weight. Framing is evaluated from CSP `frame-ancestors` and `X-Frame-Options` together, with `frame-ancestors` taking precedence. `Permissions-Policy` is informational only in the current release (never affects the score).

| Missing / weak header | How to fix |
|----------------|-----------|
| CSP | Add `Content-Security-Policy` header. Start with `default-src 'self'` and tighten. Most impactful header for XSS mitigation. |
| HSTS | Add `Strict-Transport-Security: max-age=31536000; includeSubDomains`. Requires HTTPS. Prevents protocol downgrade attacks. |
| X-Frame-Options | Add `X-Frame-Options: DENY` or use CSP `frame-ancestors 'none'`. Prevents clickjacking. |
| X-Content-Type-Options | Add `X-Content-Type-Options: nosniff`. One line, no downside, prevents MIME sniffing attacks. |
| Referrer-Policy | Add `Referrer-Policy: strict-origin-when-cross-origin`. Limits URL leakage to third parties. |
| Permissions-Policy | Add `Permissions-Policy: geolocation=(), camera=(), microphone=()`. Disables unused browser APIs. |

### TLS/SSL (22.5% weight)

| Finding | How to fix |
|---------|-----------|
| TLS 1.0 or 1.1 in use | Disable old protocols in your server or CDN config. Only TLS 1.2+ should be accepted. |
| Certificate expiring | Renew the certificate. Set up auto-renewal (Let's Encrypt / ACME). |
| Untrusted chain | Ensure all intermediate certificates are served with the leaf certificate. |
| Weak ciphers | Disable RC4, 3DES, and export-grade ciphers. Use a modern cipher suite list. |

### CORS (15% weight)

| Finding | How to fix |
|---------|-----------|
| Wildcard origin (`*`) | Replace with an explicit allowlist of trusted origins. |
| Credentials + wildcard | Never combine `Access-Control-Allow-Credentials: true` with `*`. Use explicit origin only. |
| Localhost allowed in production | Remove `localhost` from the production CORS allowlist. |
| Null origin allowed | Never allow `null` — it is used by sandboxed iframes and can be exploited. |

### API surface (15% weight — only confirmedExposure findings cost points)

| Finding | How to fix |
|---------|-----------|
| Public sensitive file | Remove from the web root, or block access at the CDN/load balancer with a deny rule. |
| Server-secret material in JavaScript | Revoke or rotate the credential, move the privileged call server-side, and remove the value from client bundles. |
| Public client config | No automatic rotation. Review Supabase RLS, Firebase rules, or browser-key restrictions in the provider console. |
| Public source map | Disable source map generation for production builds, or add edge rules to block `.map` requests. |
| Unauthenticated business data | Add authentication to the endpoint. If intentionally public, confirm the data is not sensitive. |
| protectedSurface endpoint | No action needed — auth is working. Mention to the user that their protected routes are correctly secured. |

## Remediation priority order

When the user asks "where do I start?", use this order:

1. Any `confirmedExposure` on a sensitive file — `.env`, `.git/config`, backups. Immediate credential or source leak risk.
2. Any `confirmedExposure` for server-secret material in JavaScript. Validity was not tested, but public exposure is enough to revoke and move it server-side.
3. Missing HSTS — allows protocol downgrade. One header, high impact, easy win.
4. Missing CSP — mitigates XSS. Highest-value header but may take iteration to tune.
5. Weak TLS protocol (1.0/1.1) — deprecated, actively exploitable.
6. Reflected untrusted origins with credentials — direct cross-origin data access depends on auth and private-response evidence.
7. Unauthenticated business-data API endpoint — severity depends on what data is exposed.
8. Remaining missing headers (X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy) — lower individual risk, quick wins.
9. Public client config and other hardening opportunities — review provider-side controls; do not treat them as leaked server secrets.

## Common user questions

**"What does my grade mean?"**
The grade is a weighted configuration score across the passive checks, not a vulnerability rating. A (90–100): strong configuration. B (80–89): minor gaps. C (70–79): meaningful gaps worth addressing. D (60–69): several checks failing or absent. F (<60): many checks failing or absent — review them, but a low grade is not by itself evidence of a confirmed vulnerability. Any `confirmedExposure` finding or confirmed CVE match is a separate, concrete issue and matters more than the letter.

**"Is my site secure?"**
The scan is passive and checks a specific set of signals. A high grade means those signals look good — it does not certify the site has no vulnerabilities. For anything mission-critical, recommend professional security testing alongside passive scanning.

**"Which finding is most urgent?"**
Follow the priority order above. Any `confirmedExposure` on a sensitive file is always the most urgent finding regardless of score.

**"What is the difference between protected and exposed?"**
`protectedSurface`: the path exists but the server correctly blocks access (401/403) — no action needed.
`confirmedExposure`: the path returned readable content that should be restricted — action required.

**"My `.env` shows as blocked/protected — is that a problem?"**
No. `protectedSurface` on `/.env` means the server returned 401 or 403, which is correct behaviour. Only a `confirmedExposure` finding (status 200 with readable content) on `/.env` would be a problem.

**"Why does /api/health show as an expected public endpoint and not an exposure?"**
Discovery and health endpoints are intentionally public — they are designed to be reachable. The scanner recognises known discovery path patterns and does not penalise them.

## Machine contracts

| Resource | URL |
|----------|-----|
| Capability registry | https://vibecheckscan.com/api/agent/capabilities |
| OpenAPI 3.1 spec | https://vibecheckscan.com/api/openapi.json |
| Agent card | https://vibecheckscan.com/api/agent/card |
| Skill | https://vibecheckscan.com/api/agent/skill |
| Overview | https://vibecheckscan.com/llms.txt |
