Skip to content

Check that sensitive values can actually be redacted - #1054

Merged
theoephraim merged 23 commits into
mainfrom
short-sensitive-value-warning
Sep 1, 2026
Merged

Check that sensitive values can actually be redacted#1054
theoephraim merged 23 commits into
mainfrom
short-sensitive-value-warning

Conversation

@theoephraim

@theoephraim theoephraim commented Sep 1, 2026

Copy link
Copy Markdown
Member

Redaction is substring replacement over strings. Plenty of values can be marked sensitive without that protection ever meaningfully applying, and nothing checked for it. Because @defaultSensitive=true is the default, most of these get swept in without anyone writing @sensitive at all.

Rules

Case Explicit @sensitive Via @defaultSensitive
value under 12 characters warning warning
value under 3 characters error warning
boolean error warning
number error warning
composite with non-string elements error warning
the @currentEnv item error warning
non-sensitive value containing a sensitive one warning warning

The one guarantee across all of it: nothing an item inherited from @defaultSensitive can fail a load in this release. Only an explicit @sensitive can, and the escalations noted below belong in a breaking release.

Builtin VARLOCK_* items are exempt. @sensitive={allowShortValue=true} opts out of the under-12 warning, for secrets that are short by nature (a one-time code, a PIN) and cannot be lengthened. It does not opt out of anything else.

Why each one lands where it does

Length. An ACME_ACCOUNT=acmeco rewrites every acmeco in console output and proxied response bodies, corrupting content that was never a secret. Under 3 characters there is no output that survives the redaction at all, so that one cannot be acknowledged: the ack records that a collision risk was read and accepted, and at one or two characters it is not a risk, it is a certainty. It follows the same explicit/implicit split as the type rules below, so an inherited AWS_REGION=us warns rather than failing CI.

Type rules split by who asked. An explicit @sensitive is a claim that the value is a secret, and for these types that claim is not being honored, so it fails. @defaultSensitive=true is not a claim, it is what a hand-written schema inherits, and it sweeps in every port, timeout and feature flag in the file. Those warn instead.

  • A boolean holds one bit, so there is no secret in it to protect, while redacting it would rewrite every true/false in logs and response bodies.
  • A number is never redacted at all: collectSensitiveStrings only collects string leaves, and envStr is serialized only for object values. Making it a string also keeps the leading zeros and precision past 2^53 that a number drops.
  • A composite hides the same problem from the scalar checks: @type=array(number) has a composite coercedType while every element is a number, and only string leaves are registered.
  • The @currentEnv item drives conditional imports and forEnv() and is echoed by most tools in the stack, so it is a mode name rather than a secret.

Whichever branch fires, it replaces the generic length message rather than stacking a second one on the same item.

Nothing here changes an item's sensitivity. Demoting a boolean to non-sensitive is the eventual answer, but sensitivity is what @dynamic defaults to, so demoting would also flip the item to @static and make its value eligible to be inlined into a build. That is a silent runtime behavior change that no error would announce, so it belongs in a breaking release rather than here.

Containment is reported on the non-sensitive item, since marking it sensitive is the fix. It is a warning for now and an error in a breaking release: it is the only rule here that depends on how two resolved values relate, so whether it fires depends on what a given machine's .env contains, and as a hard failure it could pass locally and fail in CI.

The length of the match still picks the advice, because it is catching two things. A long value inside a public one is a secret genuinely carried into public output; that overlaps heavily with leak detection, which already fails at runtime once the containing value reaches a response, and it also covers paths leak detection misses (build-time inlining, generated types). A short value is more likely a collision than a leak, but that collision is exactly what makes redaction rewrite the containing value everywhere it appears. The short case fires even when allowShortValue silenced the generic short-value warning, because here the collision is confirmed rather than hypothetical.

Also fixed

Two disclosure bugs in CLI output, both pre-existing on main:

  • getItemSummary and explain guarded redaction on _.isString, so a sensitive value that coerced to a number printed in cleartext while its quoted equivalent was masked. Masking now follows the item's sensitivity rather than its inferred type.
  • getItemSummary still printed resolvedRawValue unredacted in its < coerced from ... suffix, so a sensitive @type=array or @type=json item showed its full pre-coercion value in cleartext.

Notes

  • Thresholds and the shared helpers live in src/lib/sensitive-value.ts, since log redaction and proxy response scrubbing share the problem.
  • Composite values are measured per element, not as a joined string. Redaction registers each element of an array or object individually, so ["averylongsecret", "x"] puts "x" in the map even though the joined form is long. Runtime also registers a composite's serialized form, and injects public composites as that form, so the containment check includes it on both sides: a sensitive PORTS=[3000,3001] has no redactable leaves, but its joined 3000,3001 still rewrites a public value that contains it, including a public array(number) that serializes to the same string.
  • Warnings land in validationErrors, so a warned item's validationState flips from valid to warn. isValid still returns true, so nothing fails.
  • The shared plugin test helper now filters advisory warnings out of both its expected-error and unexpected-error assertions, so a plugin's fixtures are not hostage to advisory rules added in core, and an advisory warning cannot satisfy an expected error.
  • Test fixtures where sensitivity was incidental got @defaultSensitive=false or longer values, rather than loosened assertions.
  • scan.command has the same _.isString assumption when collecting values to scan files for. That is a detection gap rather than a disclosure, and changing it would affect scan's false-positive rate, so it is left alone here.
  • Item warnings surface on varlock load, which prints every item, but not on run or proxy, where checkForConfigErrors prints warn-state items only alongside failures. Reaching those paths needs a design that does not write to stderr on success, so it is out of scope here.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

bumpy-frog

The changes in this PR will be included in the next version bump.

minor Minor releases

  • @varlock/native-helper-darwin 1.18.0 → 1.19.0
  • @varlock/native-helper-linux-arm64 1.18.0 → 1.19.0
  • @varlock/native-helper-linux-x64 1.18.0 → 1.19.0
  • @varlock/native-helper-win32-x64 1.18.0 → 1.19.0
  • varlock 1.18.0 → 1.19.0

Bump files in this PR

Click here if you want to add another bump file to this PR


This comment is maintained by bumpy.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

📦 Bundle size

⚠️ grows the bundle by 32.2 KB (+0.7%)

Metric main This PR Δ
Total dist 4292.2 KB 4324.4 KB +32.2 KB (+0.7%)
JS 1645.6 KB 1656.3 KB +10.7 KB (+0.6%)
Sourcemaps 2549.8 KB 2568.7 KB +18.9 KB (+0.7%)
Type defs 96.8 KB 99.4 KB +2.6 KB (+2.7%)
Other 0.0 KB 0.0 KB

dist/ only; native binaries are versioned separately and not counted here.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 1, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
varlock-website 9ef8eac Commit Preview URL

Branch Preview URL
Sep 01 2026, 08:42 PM

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Important

The proxy path drops the new acknowledgement before evaluating its startup warning, so the documented opt-out does not work there. The warning also recommends a setting that attached @proxy items override.

Reviewed changes in 264db5fa, covering the short-sensitive-value rule, decorator parsing and validation, proxy startup reporting, serialization, tests, docs, and release metadata.

  • Validation warning: Sensitive non-empty values shorter than 12 characters now enter warn-state, with allowShortValue as an acknowledgement.
  • Proxy diagnostics: Proxy startup detects short managed values and reports their keys before constructing the child view.
  • Documentation and fixtures: The decorator and proxy docs explain collision risk, while incidental short test values were lengthened and OTP assertions permit warnings.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using azure/gpt-5.6-sol𝕏

Comment thread packages/varlock/src/cli/commands/proxy.command.ts Outdated
Comment thread packages/varlock/src/cli/commands/proxy.command.ts Outdated
…text

Redaction is substring replacement with no token boundary, so it cannot tell a
leaked secret from ordinary text that happens to match it. Nothing guarded
against this: every sensitive value was registered for redaction regardless of
length, so a short one (an org slug, an account id, a dev password) gets
rewritten wherever it appears, corrupting console output and proxied responses.

Adds an advisory validation warning surfaced by varlock load, plus
@sensitive={allowShortValue=true} for secrets that are short by nature (an OTP,
a PIN) where the collision risk is real but there is nothing to fix.
getItemSummary and explain both guarded redaction on _.isString, so a sensitive
value that coerced to a number (PIN=987654) fell through and printed in
cleartext, while its quoted equivalent was masked. Masking now follows the
item's sensitivity rather than its inferred type.

load.command already had a [REDACTED] fallback and was unaffected.
@theoephraim
theoephraim force-pushed the short-sensitive-value-warning branch from 173d170 to 311a15b Compare September 1, 2026 04:08
@theoephraim
theoephraim changed the base branch from proxy-request-signing to main September 1, 2026 04:09
@theoephraim theoephraim changed the title Warn when a sensitive value is short enough to collide with ordinary text Warn on short sensitive values, and redact non-string ones Sep 1, 2026

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

The new getItemSummary() redaction remains bypassable for explicitly coerced sensitive values, which leaves the original secret visible in CLI output.

Reviewed changes since the prior Pullfrog review, including the rewritten proxy-warning scope and the new non-string display redaction:

  • Proxy warning scope: Removed the separate proxy startup scanner and its proxy-specific remediation path.
  • Typed display redaction: Added redactSensitiveDisplayValue() to mask non-string sensitive values before rendering them.
  • CLI call sites: Applied the helper to resolved values in item summaries and to resolved and raw values in explain.
  • Regression coverage: Added focused helper and item-summary tests for inferred numeric, string, boolean, empty, and public values.
  • Release metadata: Expanded the changeset to include the non-string redaction fix.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using azure/gpt-5.6-sol𝕏

Comment thread packages/varlock/src/lib/test/sensitive-value.test.ts Outdated
@theoephraim theoephraim changed the title Warn on short sensitive values, and redact non-string ones Check that sensitive values can actually be redacted Sep 1, 2026

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

The expanded validation still permits a sensitive composite value that runtime redaction cannot protect, and boolean sensitivity now disagrees between generated types and the resolved graph.

Reviewed changes since the prior Pullfrog review, including the expanded sensitive-value rules and the fix for coerced raw-value disclosure:

  • Expanded validation: Added hard failures for extremely short values, explicit numeric sensitivity, explicit sensitivity on @currentEnv, and public values containing sensitive strings.
  • Adjusted inferred sensitivity: Demoted booleans to non-sensitive and changed numbers inherited from @defaultSensitive from errors to warnings.
  • Covered composite values: Added per-element length checks and shared recursive value collection.
  • Closed CLI disclosure: Redacted the pre-coercion value in getItemSummary() and added a regression test for that suffix.
  • Updated user guidance: Documented the new validation rules and adjusted affected fixtures.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using azure/gpt-5.6-sol𝕏

Comment thread packages/varlock/src/env-graph/lib/config-item.ts
Comment thread packages/varlock/src/env-graph/lib/config-item.ts Outdated

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes since the prior Pullfrog review, covering the fixes for the two remaining sensitivity-model mismatches.

  • Covered composite leaves: Added recursive detection of non-string leaves so explicitly sensitive composites fail and implicitly sensitive composites warn when runtime redaction cannot protect them.
  • Aligned type generation: Mirrored boolean demotion in getTypeGenInfo() while preserving the existing @proxy sensitivity override.
  • Added regression coverage: Exercised numeric array and record validation plus generated metadata for an implicitly sensitive boolean.
  • Updated documentation: Documented how mixed and numeric composite values follow scalar redaction rules.

Pullfrog  | View workflow run | Using azure/gpt-5.6-sol𝕏

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Important

The shared plugin helper can accept an advisory warning as a generic expected error, allowing plugin resolver regressions to pass unnoticed.

Reviewed changes since the prior Pullfrog review, covering the plugin fixture and shared test-helper adjustments.

  • Lengthened Dashlane fixtures: Replaced three short secret values so the tests no longer trigger the new sensitive-value warning.
  • Allowed advisory warnings: Filtered item warnings from successful pluginTest() expectations while retaining exact resolved-value assertions and failures for non-warning errors.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using azure/gpt-5.6-sol𝕏

Comment thread packages/varlock/src/test-helpers/plugin-test.ts Outdated
@pkg-pr-new

pkg-pr-new Bot commented Sep 1, 2026

Copy link
Copy Markdown

Open in StackBlitz

varlock

npm i https://pkg.pr.new/varlock@1054

@varlock/native-helper-darwin

npm i https://pkg.pr.new/@varlock/native-helper-darwin@1054

@varlock/native-helper-linux-arm64

npm i https://pkg.pr.new/@varlock/native-helper-linux-arm64@1054

@varlock/native-helper-linux-x64

npm i https://pkg.pr.new/@varlock/native-helper-linux-x64@1054

@varlock/native-helper-win32-x64

npm i https://pkg.pr.new/@varlock/native-helper-win32-x64@1054

commit: 330b98e

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes since the prior Pullfrog review, covering the shared plugin test-helper correction.

  • Filtered expected errors: Reused the non-warning error list for generic and specific expected-error assertions, preventing advisory warnings from satisfying an expected resolver failure.
  • Preserved success checks: Continued rejecting non-warning errors and comparing successful resolved values exactly.

Pullfrog  | View workflow run | Using azure/gpt-5.6-sol𝕏

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Important

The hard floor is implemented correctly, but the public option reference still promises behavior that the new commit explicitly removed.

Reviewed changes since the prior Pullfrog review, covering the revised boolean and minimum-length behavior.

  • Preserved boolean metadata: Replaced automatic boolean demotion with errors for explicit sensitivity and warnings for inherited sensitivity, leaving static and dynamic behavior unchanged.
  • Made the redaction floor absolute: Lowered the hard floor to three characters and prevented allowShortValue from acknowledging one-character or two-character values.
  • Expanded regression coverage: Added assertions for the hard floor, the acknowledgement boundary, and boolean type-generation parity.
  • Updated release guidance: Revised the changeset and most decorator guidance for the new behavior.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using azure/gpt-5.6-sol𝕏

Comment thread packages/varlock-website/src/content/docs/reference/item-decorators.mdx Outdated

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ No new issues in this delta. The previously reported allowShortValue documentation mismatch remains open.

Reviewed changes since the prior Pullfrog review, covering the expanded @currentEnv validation behavior.

  • Warned on inherited sensitivity: Added an advisory warning when @defaultSensitive makes the @currentEnv item sensitive, while retaining the error for an explicit @sensitive decorator.
  • Avoided duplicate diagnostics: Recorded type and @currentEnv plausibility findings so the generic short-value warning does not stack on top of a more specific message.
  • Updated guidance: Aligned the decorator documentation and release note with the explicit versus inherited severity split.
  • Added regression coverage: Verified explicit, inherited, and opted-out @currentEnv sensitivity states.

Pullfrog  | Fix it ➔View workflow run | Using azure/gpt-5.6-sol𝕏

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Important

The broadened containment check now reports collisions for scalar values that runtime redaction never registers.

Reviewed changes since the prior Pullfrog review, covering the expanded containment rule.

  • Broadened collision detection: Matched sensitive values from three through eleven characters inside public values and reported those matches as advisory warnings rather than leak errors.
  • Updated guidance: Revised the decorator reference and release note to explain the length-based severity split.
  • Added regression coverage: Verified that an acknowledged short string inside a public value warns while unrelated public values remain valid.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using azure/gpt-5.6-sol𝕏

Comment thread packages/varlock/src/env-graph/lib/env-graph.ts

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ No new issues in this delta. The two previously reported concerns remain open.

Reviewed changes since the prior Pullfrog review, covering the containment-severity adjustment.

  • Downgraded containment findings: Changed public values containing sensitive strings from length-dependent errors or warnings to advisory warnings at every supported match length, with updated tests, documentation, comments, and release notes.

Pullfrog  | Fix it ➔View workflow run | Using azure/gpt-5.6-sol𝕏

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Important

The scalar collision false positive is fixed, but composite serialized values can still be rewritten without the promised containment warning.

Reviewed changes since the prior Pullfrog review, covering the leaf-classification consolidation and documentation cleanup.

  • Separated leaf classes: Replaced the previous helpers with collectLeaves(), which distinguishes redactable string leaves from non-string leaves.
  • Restricted containment candidates: Stopped treating sensitive scalar numbers and booleans as runtime redaction matches, with regression coverage for a numeric port inside a public URL.
  • Clarified user guidance: Moved the full sensitive-value rules into the secrets guide and documented that allowShortValue cannot suppress the hard floor.
  • Simplified diagnostics: Consolidated explicit and inherited plausibility reporting without changing sensitivity or dynamic metadata.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using azure/gpt-5.6-sol𝕏

Comment thread packages/varlock/src/env-graph/lib/env-graph.ts Outdated

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Important

The new inherited-sensitivity warning is implemented and tested, but one public option description still states the previous behavior.

Reviewed changes since the prior Pullfrog review, covering the revised minimum-length severity policy.

  • Relaxed inherited sensitivity: Changed one-character and two-character values inherited from @defaultSensitive from errors to warnings while retaining errors for explicit @sensitive.
  • Preserved acknowledgement limits: Kept allowShortValue unable to suppress the minimum-length diagnostic in either severity branch.
  • Updated primary guidance: Revised the secrets guide and release note to describe the explicit versus inherited split.
  • Expanded regression coverage: Asserted that explicit short values fail, inherited short values warn, and acknowledged explicit short values still fail.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using azure/gpt-5.6-sol𝕏

Comment thread packages/varlock-website/src/content/docs/reference/item-decorators.mdx Outdated

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Important

The composite containment fix is incomplete for public composites, and the changed diagnostics currently break the focused test suite.

Reviewed changes since the prior Pullfrog review, covering the serialized composite containment fix and related diagnostic wording.

  • Matched serialized composites: Added each sensitive composite's process environment string to containment candidates, added regression coverage for a public scalar containing that form, and clarified non-string leaf diagnostics.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using azure/gpt-5.6-sol𝕏

Comment thread packages/varlock/src/env-graph/lib/config-item.ts
Comment thread packages/varlock/src/env-graph/lib/env-graph.ts

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes since the prior Pullfrog review, covering the final fixes for documentation, diagnostic coverage, and symmetric composite containment.

  • Updated diagnostic coverage: Aligned both explicit and inherited non-string composite assertions with the revised messages.
  • Corrected option guidance: Documented the explicit error versus inherited warning split for values under three characters.
  • Matched public composite serialization: Included public composite process-environment strings in containment matching and added a regression test for identical sensitive and public numeric arrays.

Pullfrog  | View workflow run | Using azure/gpt-5.6-sol𝕏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant