Skip to content

Post-merge hardening: CSV LF, SECURITY.md, dependabot#16

Merged
momenbasel merged 4 commits into
masterfrom
harden-followup
May 14, 2026
Merged

Post-merge hardening: CSV LF, SECURITY.md, dependabot#16
momenbasel merged 4 commits into
masterfrom
harden-followup

Conversation

@momenbasel
Copy link
Copy Markdown
Owner

@momenbasel momenbasel commented May 14, 2026

Post-merge follow-ups from auditing #15. Grew during work — scope expanded from the original 3 items to 5 commits.

Changes

js/results.js - CSV LF prefix

csvSafe already neutralised cells starting with =, +, -, @, tab, CR. Some spreadsheet parsers also evaluate LF-prefixed cells. Added \n to the prefix regex.

SECURITY.md

  • Disclosure policy
  • Threat model + in-scope / out-of-scope
  • Documents the known limitation of the nonce-validated MAIN <-> ISOLATED bridge added in v2.1.0: security hardening + cross-browser parity + release CI #15: the data-kf-verify attribute lives on documentElement between document_start and document_idle. Any page script that runs in that window can read it and forge __kf_finding__ events. Impact is bounded to displaying a fake finding in the user's results view - no data exfil, no privileged API. Mitigation cost is high because Symbols don't cross JS realms and postMessage is also page-visible.

.github/dependabot.yml

Weekly GH Actions version bumps, minor/patch grouped, max 5 open PRs.

Hardcoded v2.0 in popup + results page

Both popup.html and results.html had a hardcoded version span that went stale at the 2.0 -> 2.1.0 bump. Now reads from chrome.runtime.getManifest() at init.

Deferred window-global scan in js/interceptor.js

The globalNames scan ran at document_start when interceptor.js boots. At that point page scripts have not executed yet, so window.API_KEY / window.__NEXT_DATA__ / etc. are undefined and the entire pass was effectively dead code on real pages. Now runs at document_start, DOMContentLoaded, and load, with per-name dedupe via a scannedGlobals Set.

CHANGELOG.md

Tracks 2.0.0 and 2.1.0 releases plus an unreleased section for the contents of this PR.

Verification

  • bash scripts/build.sh builds both zips
  • web-ext lint --source-dir dist/firefox --self-hosted clean (only the two pre-existing data_collection_permissions informational warnings about strict_min_version=128)
  • semgrep p/javascript p/security-audit p/owasp-top-ten on js/: zero findings

- csvSafe now also prefixes cells starting with \n (LF). Some
  spreadsheet parsers evaluate LF-prefixed cells; the prior fix
  only handled CR and tab.
- SECURITY.md documents threat model, scope, and the known
  nonce-readable-from-page caveat in MAIN<->ISOLATED bridge
  (impact: forged finding display only, no exfil)
- Dependabot configured for weekly GH Actions version bumps
Copilot AI review requested due to automatic review settings May 14, 2026 22:23
Both popup.html and results.html had a hardcoded "v2.0" span that
went stale at the v2.0 -> v2.1.0 bump. Read chrome.runtime.getManifest()
at init time instead so it stays in sync.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread SECURITY.md

- **Per-tab badge dot** is set on the first finding only; subsequent findings update the count but not the icon
- **5000 finding cap** with FIFO eviction. High-volume scans (heavy SPAs over a long session) will drop oldest findings
- **CSV export** prefixes a single-quote on cells starting with `=`, `+`, `-`, `@`, tab, or carriage return to neutralise Excel / Sheets formula injection. Line-feed prefix is not currently neutralised
The globalNames scan ran at document_start when interceptor.js
boots. At that point page scripts have not executed yet, so
window.API_KEY / window.__NEXT_DATA__ / etc. are undefined and
the entire pass was effectively dead code on real pages.

Run scanGlobals() at document_start (cheap; catches anything
already there), then again at DOMContentLoaded, then at load.
A scannedGlobals Set dedupes so each name reports at most once.
@momenbasel momenbasel merged commit 806e0a4 into master May 14, 2026
3 checks passed
@momenbasel momenbasel deleted the harden-followup branch May 14, 2026 22:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants