Luigit
repositories / smith

smith

There are many coding harnesses - but this one is fast

owned by admin

.system/issues/SMH-ISSUE-JSONKEYS-secret-substitution-overwrites-colliding-object-keys/index.md

Raw
Rendered preview

id: SMH-ISSUE-JSONKEYS type: issue title: "Secret substitution overwrites colliding object keys" specs: [SMH-SPEC-SPEC0001] status: open

Secret substitution overwrites colliding object keys

Boundary

Secret substitution across nested object keys. Shared string transformation inherits existing last-key-wins behavior.

Evidence

smith/src/structured.rs inserts transformed keys into one map. smith-core/src/agent.rs uses this transformation for masking and authorized local unmasking. Distinct input keys can map to one output key; later insertion replaces earlier value.

let data = smith::ToolArguments::from_json(
    r#"{"secret-value":1,"{{secret:token}}":2}"#,
)?;
let masked = data.transform_strings(
    &|text| text.replace("secret-value", "{{secret:token}}"),
    64,
)?;
// Serialized result: {"{{secret:token}}":2}; first value disappeared.

Impact

Argument members disappear during secret substitution. Recorded and authorized effect inputs can lose information. No proof of filesystem escape or secret disclosure.

Resolution candidate

Reject transformed-key collisions explicitly before any effect. Diagnostic must not expose original keys or secret values. Pin nested masking and unmasking collisions with regression tests. Existing behavior changes; resolve separately from representation-only migration.

---
id: SMH-ISSUE-JSONKEYS
type: issue
title: "Secret substitution overwrites colliding object keys"
specs: [SMH-SPEC-SPEC0001]
status: open
---

# Secret substitution overwrites colliding object keys

## Boundary

Secret substitution across nested object keys.
Shared string transformation inherits existing last-key-wins behavior.

## Evidence

`smith/src/structured.rs` inserts transformed keys into one map.
`smith-core/src/agent.rs` uses this transformation for masking and authorized local unmasking.
Distinct input keys can map to one output key; later insertion replaces earlier value.

```rust
let data = smith::ToolArguments::from_json(
    r#"{"secret-value":1,"{{secret:token}}":2}"#,
)?;
let masked = data.transform_strings(
    &|text| text.replace("secret-value", "{{secret:token}}"),
    64,
)?;
// Serialized result: {"{{secret:token}}":2}; first value disappeared.
```

## Impact

Argument members disappear during secret substitution.
Recorded and authorized effect inputs can lose information.
No proof of filesystem escape or secret disclosure.

## Resolution candidate

Reject transformed-key collisions explicitly before any effect.
Diagnostic must not expose original keys or secret values.
Pin nested masking and unmasking collisions with regression tests.
Existing behavior changes; resolve separately from representation-only migration.