Skip to content

Lantern Penetration-Testing & Security-Assessment Program โ€‹

Last updated: 2026-06-12 Owner: Engineering / Security Status: Initial program definition (pre-prod; dev migration in progress) Related: SECURITY_ARCHITECTURE.md ยท SECURITY_REMEDIATION.md ยท SECRETS_MANAGEMENT.md

This document defines Lantern's ongoing, repeatable security-assessment program: what we test, how often, with which tools, who runs it, and how it ties back to the specific weaknesses found in the 2026-06 security review. It is deliberately tailored to our stack โ€” Firebase (Auth, Firestore + rules, Storage, App Check, callable Functions), Node/Express APIs on Cloud Run, BigQuery, a Discord bot, Gmail-ingest jobs, and React/Vite frontends on Cloudflare Pages, with Olm/Megolm E2EE chat โ€” rather than a generic checklist.

Why this matters for Lantern specifically. Our threat model centers on anonymity and PII minimization (see SECURITY_ARCHITECTURE.md). The most damaging failures for us are not classic RCE but authorization and data-exposure bugs: a Firestore rule that returns a peer's phone/encryptedSeed, an App Check gap that lets an attacker hit the REST API directly, a privilege-escalation path to the admin claim, or a lantern/check-in read that de-anonymizes a user's exact location. The program below is weighted accordingly.


1. Program structure & cadence โ€‹

We run a two-layer program: continuous automated testing on every change, plus periodic deep manual assessment. Neither replaces the other โ€” automated tooling catches regressions cheaply and constantly; humans find the business-logic and authorization flaws that scanners miss (BOLA/IDOR is the #1 API risk precisely because it is logic, not signature, based โ€” OWASP API1:2023).

1.1 Layer A โ€” Continuous (every PR / every merge) โ€‹

Runs in CI, fails the build on new high/critical findings. Cheap, fast, regression-focused.

  • SAST (Semgrep + CodeQL), SCA (npm audit + OSV-Scanner + Dependabot), secret scanning (gitleaks + GitHub push protection).
  • Firestore/Storage rules unit tests against the emulator (this is the single highest-leverage gate we are currently missing โ€” see ยง2.1).
  • DAST baseline scan (ZAP baseline / Nuclei) against a preview deploy for fast, high-severity-only checks (target < 5 min, per DAST CI guidance).

1.2 Layer B โ€” Periodic (scheduled, deeper) โ€‹

CadenceActivityOwner
Per release (to main/prod)Threat-model review of the diff; full DAST scan; rules-coverage review; abuse-case checklist for new endpointsEng
QuarterlyInternal focused manual pentest of one rotating surface (Firebase rules โ†’ API authz โ†’ auth/claims โ†’ cloud/IAM); dependency & IAM drift review; re-run the recurring test cases in ยง7.4Eng + advisor
AnnuallyExternal third-party pentest of the whole app; threat-model refresh; cloud config audit (GCP/Firebase IAM, Cloudflare, GitHub Actions); review of the disclosure/bug-bounty programExternal vendor
Continuous (when prod is public)Public/private VDP or bug bounty (see ยง6)External crowd

1.3 Threat-model-driven scoping โ€‹

Every periodic engagement is scoped from the threat model, not from a generic template. Maintain a short STRIDE/abuse-case table per trust boundary (client โ†” Firestore rules, client โ†” App Check โ†” callable/API, scheduler โ†” Cloud Run, Gmail ingest โ†” invoice parser, Discord โ†” issue creation). The four findings in ยง7.4 are permanent, regression-tracked scope items โ€” they get re-tested every cycle until structurally fixed, then kept as guard tests forever. This is the model Firebase itself recommends: unit-test your rules and add them to CI so enforcement can't silently regress (Firebase: test rules).


2. Firebase-specific testing โ€‹

Firebase misconfigurations are among the most common real-world findings in mobile/web pentests and bug bounties (Intigriti: hacking Firebase targets; Modern Pentest). In 2025, researchers found ~150 Firebase endpoints across top apps reachable with no authentication, leaking credentials and private messages (Cryptika). The dominant failure mode is rules that check request.auth != null but never check that the data belongs to that caller โ€” exactly the class of bug behind our deferred users/lanterns/checkins findings.

2.1 Firestore & Storage rules testing (highest priority โ€” we have none today) โ€‹

  • Build a rules unit-test suite with @firebase/rules-unit-testing (v9 API โ€” less setup, safely emulator-only) running against the Firebase Local Emulator Suite. This does not require the data migration and should be the first thing we add (SECURITY_REMEDIATION.md Phase 5 explicitly notes "No rules test suite currently exists in the repo").
  • Tests must assert both allow and deny cases per collection, per role (anon, authed-user, owner, merchant, admin), covering: read, list, create, update, delete, and field-level writes (the protected-keys blocklist, merchantId/ownerId, offers if false, the venues/venueRefreshMetadata constrained shapes already landed in Phase 5).
  • Track rules coverage via the emulator's coverage report (http://<emulator-host>/emulator/v1/projects/<project>:ruleCoverage.html) and gate merges on it โ€” uncovered rule branches are untested attack surface.
  • Storage rules: assert content-type/size validation and the merchant/admin write restrictions on /venues/*, /offers/*, and the /docs-images/* admin-delete restriction (Phase 5). Document docs-images WRITE staying at authenticated as a known, tracked gap.

2.2 App Check bypass testing โ€‹

App Check is meant to ensure only our genuine apps reach the backend; attackers routinely try to skip it by calling the Firebase REST API or SDK directly (Firebase: App Check, security checklist). Test cases:

  • Confirm callable Functions use enforceAppCheck: true (not merely consumeAppCheckToken) โ€” this is open in SECURITY_REMEDIATION.md Phase 2 and must be verified by a test that calls a function with no/invalid App Check token and expects rejection.
  • Confirm the API middleware dev-bypass (packages/shared/middleware/appCheck.js) is gated on an explicit local-only signal (!process.env.K_SERVICE / emulator host), not NODE_ENV โ€” an attacker-influenced NODE_ENV must never disable App Check. Add a negative test.
  • Attempt direct Firestore/Storage REST calls and direct callable invocation from an unattested client; expect denial once enforcement is on.

2.3 Custom-claims / privilege-escalation testing โ€‹

Our admin/merchant roles ride on Firebase custom claims, so claim-granting paths are crown-jewel attack surface.

  • Re-test the email-match admin-claim endpoints (/auth/admin/claim-role, /auth/roles/claim) โ€” they must require req.user.email === normalizedEmail and email_verified, or be removed (Phase 1 C1/C2).
  • Test the phone-token TOFU path (/auth/phone/token) rejects when authProofHash is absent (Phase 1 H1), and that lookupPhoneUser / /auth/phone/lookup no longer hand encryptedSeed+phoneSalt to unauthenticated callers โ€” that combination is an offline 6-digit-PIN brute-force primitive (Phase 1b/Phase 3 H). This is the path the web client actually uses, so test both the Functions and the auth-API surfaces.
  • Verify a normal user cannot self-assign merchantId == uid (closed in Phase 5 via offers if false, but keep the regression test).
  • Verify admin login lockout is enforced before credential verification and that reset URLs/tokens are never returned in responses (Phase 1/3).

2.4 Firebase pentest tooling & methodology โ€‹

Use these as part of quarterly Firebase-focused engagements:


3. Web / API testing โ€‹

Adopt the OWASP frameworks as our assessment standard: the Web Security Testing Guide (WSTG) for methodology, the Application Security Verification Standard (ASVS) for the requirements bar (target ASVS L2), and the OWASP API Security Top 10 (2023) for API risk coverage.

3.1 Authorization testing (our #1 web risk) โ€‹

BOLA/IDOR is the top API risk and is pure logic โ€” scanners alone won't find it (OWASP API1:2023; Imperva). For every API route that takes a user-influenced object id (venue/:id, lanterns/:id, merchant/offer ids, user ids), test cross-tenant access from a second authenticated identity and expect denial. Practical approach: maintain two test users + one merchant + one admin and replay each authenticated request swapping identities/ids โ€” this is the "multi-profile" authz scan pattern (StackHawk). Also cover BOPLA (mass assignment / excess data exposure โ€” our ...data spreads and over-broad doc returns) and BFLA (function-level: the /consolidate, /refresh/scheduled admin-only routes in Phase 4).

3.2 DAST tooling โ€‹

Run a layered DAST stack (the consensus is to run more than one โ€” "ZAP explores the unknown; Nuclei validates the known" โ€” Rafter):

  • OWASP ZAP โ€” full crawler/proxy/active scanner. Use zap-api-scan with our OpenAPI specs to hit every endpoint; ZAP's GitHub Actions (zaproxy/action-baseline, action-full-scan, action-api-scan) emit SARIF straight into GitHub code scanning. Baseline scan per-PR; full scan per-release.
  • Nuclei โ€” fast template-based checks for known issues + security headers; ideal pipeline-native per-PR gate.
  • Burp Suite (Pro for manual quarterly work; Burp Suite DAST is the renamed enterprise/CI product as of April 2025 โ€” comparison) โ€” primary tool for human-driven testing, especially authz and request tampering.

3.3 API fuzzing โ€‹

Fuzz the Express/Cloud Run APIs and callable wrappers: malformed JSON, type confusion, oversized payloads, unicode/escaping (we have unescaped-setHTML and email-interpolation findings โ€” Phase 3/6), missing rate limits (analytics /track, lanterns reads โ€” Phase 4). Validate that error bodies are generic (Phase 4 made BQ/GitHub/Octokit errors generic โ€” assert no internal detail/jobId leaks back to clients). Schema-aware fuzzing from the OpenAPI spec (ZAP active scan / Burp + spec import) gives the best coverage.


4. SAST / SCA / secret scanning (layering + current gaps) โ€‹

CI already runs gitleaks, CodeQL, and Semgrep โ€” strong foundation. The recommended industry pattern, used by e.g. LinkedIn, is to run Semgrep and CodeQL together because they are complementary: Semgrep gives fast pattern-level PR feedback (seconds), CodeQL does deeper semantic, multi-step dataflow analysis on a schedule (Konvu; InfoQ on LinkedIn). Keep both.

4.1 SAST โ€‹

  • Semgrep in CI on every PR for instant feedback; CodeQL nightly/scheduled for deep analysis. Both output SARIF into GitHub code scanning.
  • Add custom Semgrep rules for our recurring footguns (already flagged in Phase 7): unescaped setHTML/template interpolation, NODE_ENV-based auth/App-Check bypass, unauthenticated callables, reset-token-in-response, if true / expired-date Firestore rules, missing enforceAppCheck. Custom rules turn one-time review findings into permanent regression gates.

4.2 SCA / dependency scanning โ€‹

No single advisory DB is complete (NVD, GHSA, OSV each miss things) โ€” layer them (Rafter SCA; Jit: OSV vs npm-audit):

  • npm audit in every CI build (ecosystem-native baseline) โ€” Phase 8 already calls for npm audit fix + targeted runtime bumps; record residual dev-only advisories.
  • OSV-Scanner (Google, OSS, multi-ecosystem, lockfile-aware) as a second source โ€” recommended free pairing alongside Dependabot.
  • Dependabot (free on GitHub, auto-fix PRs) or Renovate (more configurable, grouped updates) for automated upgrades. Pick one to avoid PR noise; Dependabot is the zero-setup default for our GitHub repos.
  • Optionally Snyk (free tier) for reachability analysis if false-positive triage becomes a burden.
  • Known gap: SCA tools can't flag end-of-life packages whose CVEs are no longer tracked (Sonatype 2025 found 167k such false negatives โ€” Ciphers Security). Add a manual EOL/maintenance check to the annual review.

4.3 Secret scanning โ€‹

  • gitleaks in CI (have it) + pre-commit/pre-push hook running gitleaks on changed files (Phase 7) so secrets never reach a commit locally.
  • Enable GitHub secret scanning + push protection repo-wide โ€” it blocks secrets before they land, complementing gitleaks' detect-after-commit model (Semgrep vs GHAS).
  • Open operator action (history is still leaky): the leaked GitHub PAT and old .env/.runtimeconfig.json are redacted in the working tree but remain in git history and are still fetchable from origin. Rotate the PAT and scrub history (git filter-repo/BFG) โ€” SECURITY_REMEDIATION.md Operator actions. Secret scanning does not retroactively invalidate a live committed token; rotation is mandatory.

5. Cloud / infrastructure โ€‹

5.1 GCP / Firebase IAM review (quarterly drift + annual deep) โ€‹

  • Replace primitive roles (Editor/Owner) on service accounts with least-privilege predefined roles; give Cloud Run services a user-managed service account with minimal permissions, not the default Compute SA (Google: securing Cloud Run with least privilege; GCP SA best practices).
  • Run the IAM Recommender / Policy Analyzer on a schedule to find and cut over-provisioned permissions based on real usage (Google IAM best-practices checklist 2025).
  • Audit Firestore/Storage rules deploy permissions and the Functions/Admin-SDK service accounts (the Admin SDK bypasses rules entirely โ€” anything it touches is implicit trust).

5.2 Cloud Run config review โ€‹

  • Verify each service is not unauthenticated unless intended; the schedulerโ†’Cloud Run path should use OIDC / a shared scheduler secret that fails closed โ€” Phase 4 replaced the spoofable X-CloudScheduler-JobName header with the SCHEDULER_SECRET bearer guard (operator must set it or /venues/refresh/scheduled 403s by design). Confirm ingress settings, min-instances, and that secrets come from Secret Manager, not env literals.

5.3 Cloudflare config (Pages frontends) โ€‹

  • Review security headers / CSP (we have a CSP-wildcard-adjacent risk โ€” a 2025 Firestore+CSP-wildcard chain produced unauth RCE; avoid * in script-src), geolocation=(self) Permissions-Policy (already set), TLS settings, WAF/rate-limit rules, and that no preview deployments expose privileged endpoints.

5.4 GitHub Actions supply-chain hardening โ€‹

The tj-actions/changed-files compromise (CVE-2025-30066, March 2025) dumped CI runner memory and exposed secrets to logs across 23,000+ repos; tags were retroactively repointed to malicious code, so tag-based pinning offered no protection. Root cause traced to a leaked token from reviewdog/action-setup (CVE-2025-30154) (CISA; Wiz; Unit 42). Hardening for our workflows:

  • Pin every third-party action to a full commit SHA, not a tag โ€” repos pinned by SHA were unaffected. Use Dependabot to bump the pins.
  • Least-privilege GITHUB_TOKEN: default permissions: {} at workflow top, grant per-job only what's needed.
  • Use OIDC / Workload Identity Federation for GCP and Cloudflare deploys โ€” short-lived token exchange, no long-lived key files (GCP best practices).
  • Fix script injection: move ${{ github.event.* }} / head_ref into env: before use (Phase 7 H โ€” issue-triage.yml, deploy-preview.yml). Untrusted input interpolated into a run: block is RCE on the runner.
  • Restrict which actions can run (allow-list), and review the Gmail-ingest and Discord-bot pipelines (untrusted external input โ†’ invoice parser / issue creation) for injection.

6. External options (third-party pentest & bug bounty) โ€‹

Pentest and bug bounty are complementary: a pentest is a time-boxed, scoped, methodical deep-dive (good for compliance, new releases, a known surface); a bug bounty is continuous, breadth-first, pay-per-valid-bug coverage from many researchers (DeepStrike: pentest vs bug bounty). For a privacy-first social app, an annual external pentest plus a disclosure program is the right baseline; a paid bounty comes once there's real prod traffic worth attacking.

6.1 Platforms โ€‹

  • HackerOne โ€” largest researcher community/program volume; platform fees start around $20K/yr + payouts (Vendr).
  • Bugcrowd โ€” comparable pricing/managed packaging to Intigriti.
  • Intigriti โ€” strong in EU; VDP $10Kโ€“$30K/yr, managed bug bounty ~$50Kโ€“$150K/yr mid-market; also offers flexible PTaaS (Vendr; AppSentinels). Multi-year commitments commonly unlock 15โ€“30% discounts.

6.2 What a pre-prod startup should realistically do (and budget) โ€‹

  1. Now (โ‰ˆ$0): Stand up a Vulnerability Disclosure Policy (VDP) โ€” we already advertise security@ourlantern.app and a VULNERABILITY_DISCLOSURE.md (referenced in SECURITY_ARCHITECTURE.md). A clear safe-harbor + scope + security.txt costs nothing and is the highest-ROI first step. Don't run a paid bounty pre-prod โ€” you'd pay for noise against a moving target.
  2. At/near public launch (โ‰ˆ$5Kโ€“$15K): A single scoped external pentest or PTaaS sprint focused on the crown jewels (Firebase rules, auth/claims, API authz). Cheaper and more predictable than a full annual retainer for an early app.
  3. Once there's real traffic ($20K+/yr): A private, invite-only bug bounty (HackerOne/Intigriti) โ€” scoped, capped budget, vetted researchers โ€” before ever going public. This matches the operator preference to finish the devโ†’prod migration before any prod exposure.

7.1 Guiding constraints โ€‹

  • Pre-prod, dev migration in progress. Prioritize work that needs no prod and no data migration first (rules tests, App Check enforcement tests, custom Semgrep rules, CI hardening). Do not stand up paid prod-facing testing yet โ€” that's deferred until the operator declares prod readiness.
  • Anonymity/PII is the prize. Weight everything toward authorization and data-exposure testing.

7.2 Phased rollout (priority order) โ€‹

Phase A โ€” Foundation (weeks 1โ€“2, no prod needed) โ€” START HERE

  1. Build the @firebase/rules-unit-testing suite against the emulator; add to CI as a required gate. Cover every collection ร— role ร— operation, including the Phase 5 field-level changes. Wire up rules coverage reporting. (Closes the single biggest gap: no rules tests exist today.)
  2. Add negative tests for App Check enforcement (callable with bad token โ†’ reject; API dev-bypass only fires on local signal, not NODE_ENV).
  3. Add custom Semgrep rules for the recurring footguns (ยง4.1).
  4. CI/CD hardening: SHA-pin actions, least-privilege GITHUB_TOKEN, fix ${{ github.event.* }} injection, enable GitHub secret scanning + push protection, add the pre-push gitleaks hook.

Phase B โ€” Continuous DAST + SCA (weeks 3โ€“4) 5. Add ZAP baseline + Nuclei scans against preview deploys per PR (SARIF โ†’ code scanning); ZAP full scan + OpenAPI import per release. 6. Layer OSV-Scanner alongside npm audit; settle on Dependabot for auto-fix PRs; clear the Phase 8 advisories.

Phase C โ€” First manual authz pass (month 2) 7. Internal BOLA/BFLA sweep with the two-user + merchant + admin identity matrix across every id-bearing route; verify the ยง7.4 recurring cases. 8. Firebase-focused pass with firepwn against the dev project.

Phase D โ€” Pre-launch external test (gated on prod readiness, operator-initiated) 9. Scoped external pentest / PTaaS sprint (crown jewels). 10. Publish the VDP + security.txt; prepare a private bug bounty to switch on post-launch.

7.3 Tooling checklist โ€‹

LayerToolRoleCadenceCostStatus
Rules testing@firebase/rules-unit-testing + Emulator SuiteFirestore/Storage authz unit tests + coveragePer PRFreeAdd (Phase A)
Firebase pentestfirepwnClient-SDK-driven rules/authz attacksQuarterlyFreeAdd (Phase C)
SASTSemgrep (+ custom rules)Fast PR pattern analysisPer PRFree/CEHave; add custom rules
SASTCodeQLDeep semantic dataflowNightlyFree (public)Have
SCAnpm auditEcosystem baselinePer buildFreeHave/expand
SCAOSV-ScannerMulti-source advisory scanPer PRFreeAdd (Phase B)
SCADependabotAuto-fix PRsContinuousFreeAdd (Phase B)
Secretsgitleaks (+ pre-push hook)Detect committed secretsPer PR + localFreeHave; add hook
SecretsGitHub secret scanning + push protectionBlock secrets pre-mergeContinuousFree (public repo)Enable (Phase A)
DASTOWASP ZAPCrawl/active scan + OpenAPIPR baseline / release fullFreeAdd (Phase B)
DASTNucleiTemplate/known-issue + headersPer PRFreeAdd (Phase B)
DAST/manualBurp Suite (Pro/DAST)Human authz + tamperingQuarterly/releasePaidAdd (Phase C)
Cloud IAMGCP IAM Recommender / Policy AnalyzerLeast-privilege driftQuarterlyFreeAdd (Phase B/C)
CI hardeningSHA-pinned actions + OIDC/WIFSupply-chainContinuousFreeAdd (Phase A)
ExternalVDP + (later) private bug bountyCrowd coverageContinuous post-launch$0 โ†’ $20K+/yrPhase D
ExternalThird-party pentest / PTaaSDeep scoped assessmentPre-launch + annual~$5Kโ€“$15K+Phase D

7.4 Recurring test cases (regression-tracked forever โ€” tie to the 2026-06 audit) โ€‹

These four audit findings become permanent test cases, re-run every quarter and every release until structurally fixed, then kept as guard tests:

  1. PII exposure via Firestore rules (users returns phone/phoneHash/salts/encryptedSeed; lanterns/checkins over-broad โ€” deferred D1โ€“D3). Rules test: a non-owner authed user (and an anon user) reading another users doc must get only public-profile fields, never PII; list must be denied; lantern reads must not expose userId + raw coords.
  2. App Check enforcement (Phase 2). Test: callable Functions reject missing/invalid App Check tokens (enforceAppCheck: true); API bypass fires only on a real local signal, not NODE_ENV; direct REST/SDK calls from an unattested client are denied.
  3. Auth privilege-escalation (Phase 1/1b/3). Test: no anonymous retrieval of encryptedSeed+salt (offline PIN brute-force); claim-grant endpoints require verified email match or are gone; TOFU phone-token path rejects absent authProofHash; no user can self-assign merchantId; admin lockout enforced before verify; no reset tokens in responses.
  4. Location de-anonymization (D2, SECURITY_ARCHITECTURE.md location model). Test: public lantern/check-in reads expose aggregate counts only โ€” never userId + exact coordinates; server truncates coords in lightLantern; no raw-coord ...data spread in getVenueLanterns; presence/check-in reads are venue/geo-scoped, not bulk-listable.

7.5 Cadence calendar โ€‹

CadenceActivities
Every PRSemgrep, CodeQL (or nightly), gitleaks + push protection, npm audit + OSV-Scanner, rules unit tests + coverage, ZAP baseline + Nuclei on preview
Every merge to devFull CI gate above must pass and be blocking (Phase 7)
Every release to main/prodThreat-model review of diff; ZAP full scan + OpenAPI; rules-coverage review; re-run ยง7.4 recurring cases; abuse-case checklist for new endpoints
QuarterlyRotating manual pentest (Firebase rules โ†’ API authz โ†’ auth/claims โ†’ cloud/IAM); firepwn pass; GCP IAM Recommender + action-pin drift review; dependency EOL review
AnnuallyExternal third-party pentest; threat-model refresh; full cloud config audit (GCP/Firebase IAM, Cloudflare CSP/WAF, GitHub Actions); review disclosure/bounty program; publish a redacted summary (per our transparency commitment)
Continuous (post-launch)VDP intake; later, privateโ†’public bug bounty

8. Sources โ€‹

Built with VitePress