Relationships
#3641 Generated vault keys carry raw data-name and vary characters that strict vault providers reject
Opened by zack · 10/19/2026
Problem
processSensitiveResourceData (src/domain/models/data_writer.ts) builds a sensitive field's generated vault key from <modelType>/<modelId>/<method>/<spec>/<instanceName>/<fieldPath> and passes it through sanitizeVaultKey, which only handles @, /, \, ', .. and NUL. Everything else in the instance name reaches the vault provider as-is.
Since swamp-club#3633 the instance segment includes the vary suffix, and vary values are much more likely than hand-picked data names to hold characters such as spaces, braces, double quotes, colons and commas. coerceToSuffix (src/domain/workflows/data_suffix.ts) falls back to truncated JSON for an object without key, name or id, so a vary input like {region: us} becomes a suffix of {"region":"us"}, and a string input us east keeps its space.
local_encryption accepts these characters. Providers with stricter key rules may refuse the put, so the write fails. AWS Secrets Manager, for example, allows only alphanumerics and /_+=.@-. A data name holding these characters could already trigger this before #3633; vary makes it far more likely.
Expected
The instance segment of a generated key is normalised to a conservative character set (for example [A-Za-z0-9._-]) in a way that keeps distinct instance names distinct, for example a short hash suffix whenever characters had to be replaced, so two vary instances never fold onto one key again.
Notes
- Raised by the adversarial review of the swamp-club#3633 fix. Out of scope there: it changes the key-derivation design rather than which name is passed.
- Stored references carry the key literally, so changing the derivation affects new writes only.
- An explicit field
vaultKeyis not sanitised and is out of scope. - A pre-existing related collision: segments are joined with
-after sanitising, so speca-bwith instancecand specawith instanceb-cproduce the same key. A redesign of the instance segment could address both.
Open
No activity in this phase yet.
zack commented 10/19/2026, 9:29:47 PM
Scope update from swamp-club#3633. Testing after its first verification showed the vary suffix could not reach the key raw without regressions (a quote vs a dash and an at-sign vs nothing folded onto one key; a 200-character plain value hit File name too long in local_encryption). So #3633 now encodes the vary suffix itself: kept as written when it is at most 64 letters, digits, dot, underscore and dash, otherwise a plus sign and 32 hex digits of its SHA-256. What remains here is the base data name (and the rest of the key), which still passes through sanitizeVaultKey alone, plus the spec/instance split ambiguity noted above. A non-vary data name with characters outside the safe set, or a very long one, still has both problems.
zack commented 10/19/2026, 9:41:07 PM
Further scope from swamp-club#3633. The vary suffix is now kept as written only when it is at most 32 letters, digits and dashes, and is otherwise hashed to h- plus 32 hex digits (34 characters, all Azure Key Vault safe), so a vary write's key is at most 35 bytes longer than the same write without vary. That bounds the suffix, not the key. A behavior whose type, method, spec and field names already produce a key near the 255-byte local_encryption file name still overflows it, with or without vary (a test behavior with type user/very-long-vendor-name/service-category/resource-type-name, method [REDACTED-SECRET-1] and a nested field has a 210-byte key before any suffix). A real guarantee needs a cap on the whole generated key, which belongs here with the base-name normalisation. The same applies to Azure Key Vault: a dot in a nested field path or an underscore elsewhere in the key is still passed through, and Azure also caps names at 127 characters.
Sign in to post a ripple.