Summary
declare, readonly, local, and export builtins insert directly into the variables HashMap via ctx.variables.insert() or self.variables.insert(), bypassing the is_internal_variable() guard in set_variable().
Impact — HIGH
Attacker-controlled scripts can:
- Create unauthorized namerefs:
declare _NAMEREF_alias=secret → $alias resolves to $secret
- Inject case conversion attributes:
declare _UPPER_x=1 → all assignments to x are uppercased
- Pollute internal state with fake readonly/nameref/case markers
Reproduction
# Unauthorized nameref creation
secret="sensitive_data"
declare _NAMEREF_alias=secret
echo "$alias" # prints "sensitive_data"
# Case conversion injection
declare _UPPER_myvar=1
myvar="should be lowercase"
echo "$myvar" # prints "SHOULD BE LOWERCASE"
Affected code
| Builtin |
File |
Line |
Insert path |
declare |
interpreter/mod.rs |
5574 |
self.variables.insert(var_name, final_value) |
readonly |
builtins/vars.rs |
265 |
ctx.variables.insert(name, value) |
local (outside fn) |
interpreter/mod.rs |
4599 |
self.variables.insert(var_name, value) |
local (inside fn) |
interpreter/mod.rs |
4572 |
frame.locals.insert(var_name, value) |
export |
builtins/export.rs |
41 |
ctx.variables.insert(name, value) |
Recommended fix
Add is_internal_variable() check before each insert. Best long-term fix: route all variable mutations through set_variable() or use a separate HashMap for internal markers (per TM-INJ-009 recommendation).
Tests
Regression tests in tests/security_audit_pocs.rs (currently #[ignore]):
security_audit_declare_blocks_nameref_prefix
security_audit_declare_blocks_upper_prefix
security_audit_declare_blocks_lower_prefix
security_audit_readonly_blocks_nameref_prefix
security_audit_export_blocks_readonly_prefix
security_audit_local_blocks_internal_prefixes
Remove #[ignore] when fix lands.
Cross-references
Summary
declare,readonly,local, andexportbuiltins insert directly into the variables HashMap viactx.variables.insert()orself.variables.insert(), bypassing theis_internal_variable()guard inset_variable().Impact — HIGH
Attacker-controlled scripts can:
declare _NAMEREF_alias=secret→$aliasresolves to$secretdeclare _UPPER_x=1→ all assignments toxare uppercasedReproduction
Affected code
declareinterpreter/mod.rsself.variables.insert(var_name, final_value)readonlybuiltins/vars.rsctx.variables.insert(name, value)local(outside fn)interpreter/mod.rsself.variables.insert(var_name, value)local(inside fn)interpreter/mod.rsframe.locals.insert(var_name, value)exportbuiltins/export.rsctx.variables.insert(name, value)Recommended fix
Add
is_internal_variable()check before each insert. Best long-term fix: route all variable mutations throughset_variable()or use a separate HashMap for internal markers (per TM-INJ-009 recommendation).Tests
Regression tests in
tests/security_audit_pocs.rs(currently#[ignore]):security_audit_declare_blocks_nameref_prefixsecurity_audit_declare_blocks_upper_prefixsecurity_audit_declare_blocks_lower_prefixsecurity_audit_readonly_blocks_nameref_prefixsecurity_audit_export_blocks_readonly_prefixsecurity_audit_local_blocks_internal_prefixesRemove
#[ignore]when fix lands.Cross-references