Open a private security advisory on the repo: https://github.com/arcbaslow/gtm-diff/security/advisories/new
Please do not file public issues for security problems.
gtm-diff reads a GTM container export and writes a report. A container
export is not inert data: it contains Custom HTML tags and Custom
JavaScript variables, which are arbitrary attacker-authored code, and it
may contain API keys, measurement IDs, and internal hostnames in tag
parameters. The tool must never execute that code and must never leak it
somewhere the operator did not ask for.
- A regression in HTML-reporter escaping (
src/reporters/html.ts). Container exports contain Custom HTML tags. Every interpolation of container-derived data currently goes throughescapeHtml, and tests cover both the value path and the entity-name path. If you find one that does not, report it — a diff report is exactly the artifact a reviewer opens in a browser without thinking, so this is the highest-value bug class here. - A regression in
sanitizeLabel(src/reporters/shared.ts). Human-readable entity labels are stripped of C0/C1 control characters before they reach a reporter, because a name carrying ESC sequences could move the cursor and paint over lines the console reporter already printed, hiding one change behind another. - A regression in Markdown escaping or value formatting (
src/reporters/markdown.ts,src/reporters/shared.ts). HTML fragments useescapeHtml, labels usesanitizeLabel, and paths/values visibly escape C1 controls and Unicode line separators as well as JSON's C0 escapes. A report must not allow export text to change its markup or terminal structure. - A regression in JSON escaping (
src/reporters/json.ts). Source/target display labels usesanitizeLabel. Data strings and property names use reversible JSON escapes for controls, line separators and markup characters before every serialized line passes throughsanitizeLabel. Parsed values remain exact untrusted data and require context-specific escaping when rendered. See the JSON contract. - Any path where parsing an export executes code from it, including
eval,Function, dynamicimport, or prototype pollution throughJSON.parseoutput reaching an object merge. - Path traversal or arbitrary write through
--output. - Anything that sends container contents off the machine.
diffis offline and must stay offline. - Dependency-chain vulnerabilities in
@oclif/core,chalk, ormicrodiff.
- Secrets you committed into a container export that is itself in a public repo. The tool reads what you hand it.
- Bugs in Google Tag Manager or its export format — report those to Google.
- The unimplemented
planandapplycommands. Whenapplylands, its OAuth handling and write path become the top scope item; until then there is nothing to report.
The diff command requires no credentials. It takes two local JSON files, makes no network or API calls, and writes its report only to the requested output (or stdout).
The optional GitHub Action reads explicitly configured path/boolean inputs
and runner output-file settings from the environment. It writes reports to
a fresh runner-temporary directory and appends paths/status to
GITHUB_OUTPUT. Its optional job summary contains only counts and coverage
status. It reads no GTM credentials and does not upload reports or post
comments. Action setup installs the pinned tool's dependencies; comparison
code and tests remain offline. Caller-configured artifact uploads can
disclose export values, including secrets. See the Action contract.
That changes at v0.3. apply will require a bring-your-own OAuth client,
default to dry-run, operate only in a newly created workspace, never
publish, and never delete a workspace.
I aim to acknowledge security reports within 7 days and ship a fix or mitigation within 30 days. For high-severity issues, both windows shrink.