Skip to content

Filename-only "potentially sensitive" filter silently drops design-token files (tokens.css, tokens.contract.json) #2498

Description

@singhsatyampratap

Problem

A filename-word denylist silently excludes files from the graph. It matches on the name only
the content is never inspected — so design-system files called tokens.css / tokens.contract.json
are treated as credentials and dropped.

Discovered on a monorepo whose design tokens are generated artifacts with fixed names: the generated
tokens.css and the committed tokens.contract.json were both absent from the graph, announced by a
single line:

[graphify extract] 1 file(s) skipped as potentially sensitive (rename or move if wrongly flagged): tokens.css

Repro (deterministic on 0.9.34)

mkdir case && cd case
for n in tokens token mytokens design-tokens palette secrets credentials; do
  echo ':root{ --a: #fff; }' > "$n.css"
done
echo 'def f(): return 1' > tokens.py
echo '{"a":1}' > tokens.json
echo '{"a":1}' > plain.json
graphify extract . --code-only --no-cluster --out /tmp/out --force
[graphify extract] found 2 code, 0 docs, 0 papers, 0 images
[graphify extract] 2 file(s) not classified (no supported extension or shebang), skipped: mytokens.css, palette.css
[graphify extract] 6 file(s) skipped as potentially sensitive (rename or move if wrongly flagged):
      credentials.css, design-tokens.css, secrets.css, token.css, tokens.css, tokens.json

The rule, as observed

file outcome
tokens.css, token.css, design-tokens.css, secrets.css, credentials.css, tokens.json skipped as sensitive
mytokens.css, palette.css not matched
tokens.py not matched
plain.json indexed

Three properties, all of which look unintended:

  1. Content is never read. An empty file named token.css is skipped; a file named palette.css
    containing a real API key is not. The check cannot do what its message claims.
  2. The match is word-boundary aware, which makes it worse, not better. design-tokens matches
    (separator-delimited word tokens), mytokens does not. So the more conventionally named a
    design-token file is, the more likely it is to be dropped.
  3. It is extension-dependent. tokens.py survives; tokens.css and tokens.json do not. Same
    word, same content-blindness, different outcome. (Also note .css is not a supported code
    extension at all — palette.css came back "not classified" — yet tokens.css still went down the
    sensitive path, so the check runs ahead of classification.)

Why the suggested remedy does not work

The warning says "rename or move if wrongly flagged". For a generated artifact that is not
available: the name is fixed by the generator and asserted by a drift guard in CI. Renaming it to
please a scanner would break the build that produces it. In a design-system repo, tokens.* is close
to the single most likely filename to exist.

Suggested fix

Any of these would resolve it; roughly in order of preference:

  1. Inspect content. Gate the skip on an actual secret-shaped match (high-entropy string, known key
    prefixes, PRIVATE KEY armor). A :root{} block of hex colours is not that.
  2. Drop token from the name denylist, or require it to co-occur with a content signal.
    secret/credential/password are far less ambiguous than token, which is ordinary vocabulary
    in design systems, tokenizers, parsers and lexers.
  3. Make it overridable — honour a .graphifyignore-style allowlist, or add
    --no-sensitive-filter. Today there is no flag to opt out; I checked --help.
  4. Raise the reporting. One line in the middle of extraction output is easy to miss for a file
    that then simply does not exist in the graph. If a file is excluded, it is worth being loud.

Happy to send a PR for (1) or (3) if you have a preference on shape.

Environment

graphifyy 0.9.34, macOS (darwin 25.5.0), Python 3.12, --code-only (no LLM backend involved).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions