What problem are you trying to solve?
Summary
nono already treats "what counts as dangerous" as policy. Risky directories, credentials, and commands are all declared in policy.json, where they can be read, reasoned about, and adjusted without touching the source.
Environment variables are the single exception: the list of dangerous variables is compiled into the binary. It cannot be inspected as policy, it cannot be extended without cutting a new release, and it is the only category of risk that does not follow nono's usual "configure it in policy" pattern.
This issue proposes bringing environment variables into line with everything else.
Why it matters
Three practical problems follow from the list living in code rather than in policy:
-
Consistency. An operator who has learned to manage dangerous paths, credentials, and commands in policy.json reasonably expects environment variables to behave the same way. At present they are a special case, tucked away where only contributors will ever find them.
-
Operational flexibility. When a newly discovered variable needs to be blocked, the current model requires a code change, a release, and everyone to upgrade. It ought to be a one-line change to a configuration file that takes effect at once.
-
Transparency. Once the list lives in policy, each entry can carry a short note explaining why it is there. It becomes documentation as well as enforcement, rather than an opaque function no operator ever sees.
What this is not
To be clear about scope: this is not a security hole. The dangerous list is already applied before allow_vars, so a wildcard such as allow_vars: ["*"] cannot let a dangerous variable slip through; the default-deny behaviour is correct as it stands.
The proposal concerns configurability and consistency.
What it might look like
The natural model already exists in the codebase: dangerous commands. They are declared as policy data, and the same approach maps cleanly onto environment variables, provided one safeguard is kept.
-
The set becomes policy data, extensible per profile or per organisation, much as the dangerous_commands group is today.
-
A core set remains compiled in and cannot be removed. The most serious offenders — the loader-injection variables and the secret-bearing tokens — should stay a fixed floor that policy may extend but never shrink or weaken, so that a malformed or empty policy file can never quietly disarm protection. (nono's existing required: true flag only prevents a whole group from being deleted; it does not stop an individual entry from being waived, so this floor genuinely needs to live in code. Should the policy fail to load, nono ought to refuse to run rather than continue unprotected.)
-
An optional, narrowly scoped exception. Where a tool has a genuine need for a variable that is dangerous by default, the same model could permit it to be named explicitly for a single command — never through a wildcard. This is a secondary convenience, not the point of the change.
Points worth getting right
-
The list must be able to express whole families of names (LD_*, DYLD_*, and so on), not merely exact matches; a straight conversion that only carried exact names would silently lose coverage.
-
The behaviour must be identical on Linux and macOS, both of which apply the same check.
-
There is a second, separate dangerous-variable list in keystore.rs, and a distinct set_vars path that behaves differently again. Both should be reconciled with the policy model, rather than left as three sources of truth.
Acceptance criteria
What would you like to see?
I would like dangerous environment variables to be managed through policy.json, in the same way dangerous commands, paths, and credentials already are, rather than being hardcoded in the binary.
Concretely:
-
The dangerous-variable set declared as policy data, modelled on the existing dangerous_commands group, so it can be reviewed, documented entry by entry, and extended without cutting a new release.
-
A small core — the loader-injection variables and the secret-bearing tokens — kept compiled in as a floor that policy may extend but never remove or weaken, with nono refusing to start if the policy fails to load.
-
The model able to express whole name families (LD_*, DYLD_*), to behave identically on Linux and macOS, and to account for the second list in keystore.rs and the separate set_vars path.
-
Optionally, a narrowly scoped, by-name exception for the rare command that genuinely needs an otherwise-dangerous variable — never through a wildcard.
In short: environment variables brought into line with every other category of risk — configured in policy, documented in the open, with a non-removable safety floor retained in code.
What have you tried instead?
No response
How is this blocking you?
Just an idea — low urgency
Additional context
No response
What problem are you trying to solve?
Summary
nono already treats "what counts as dangerous" as policy. Risky directories, credentials, and commands are all declared in
policy.json, where they can be read, reasoned about, and adjusted without touching the source.Environment variables are the single exception: the list of dangerous variables is compiled into the binary. It cannot be inspected as policy, it cannot be extended without cutting a new release, and it is the only category of risk that does not follow nono's usual "configure it in policy" pattern.
This issue proposes bringing environment variables into line with everything else.
Why it matters
Three practical problems follow from the list living in code rather than in policy:
Consistency. An operator who has learned to manage dangerous paths, credentials, and commands in
policy.jsonreasonably expects environment variables to behave the same way. At present they are a special case, tucked away where only contributors will ever find them.Operational flexibility. When a newly discovered variable needs to be blocked, the current model requires a code change, a release, and everyone to upgrade. It ought to be a one-line change to a configuration file that takes effect at once.
Transparency. Once the list lives in policy, each entry can carry a short note explaining why it is there. It becomes documentation as well as enforcement, rather than an opaque function no operator ever sees.
What this is not
To be clear about scope: this is not a security hole. The dangerous list is already applied before
allow_vars, so a wildcard such asallow_vars: ["*"]cannot let a dangerous variable slip through; the default-deny behaviour is correct as it stands.The proposal concerns configurability and consistency.
What it might look like
The natural model already exists in the codebase: dangerous commands. They are declared as policy data, and the same approach maps cleanly onto environment variables, provided one safeguard is kept.
The set becomes policy data, extensible per profile or per organisation, much as the
dangerous_commandsgroup is today.A core set remains compiled in and cannot be removed. The most serious offenders — the loader-injection variables and the secret-bearing tokens — should stay a fixed floor that policy may extend but never shrink or weaken, so that a malformed or empty policy file can never quietly disarm protection. (nono's existing
required: trueflag only prevents a whole group from being deleted; it does not stop an individual entry from being waived, so this floor genuinely needs to live in code. Should the policy fail to load, nono ought to refuse to run rather than continue unprotected.)An optional, narrowly scoped exception. Where a tool has a genuine need for a variable that is dangerous by default, the same model could permit it to be named explicitly for a single command — never through a wildcard. This is a secondary convenience, not the point of the change.
Points worth getting right
The list must be able to express whole families of names (
LD_*,DYLD_*, and so on), not merely exact matches; a straight conversion that only carried exact names would silently lose coverage.The behaviour must be identical on Linux and macOS, both of which apply the same check.
There is a second, separate dangerous-variable list in
keystore.rs, and a distinctset_varspath that behaves differently again. Both should be reconciled with the policy model, rather than left as three sources of truth.Acceptance criteria
The dangerous-variable set is expressible in policy (modelled on
dangerous_commands), extensible without a release, and able to describe name families such asLD_*.A compiled-in core remains that policy can extend but never remove or weaken; a failed policy load causes nono to abort rather than run unprotected.
If the optional exception is included, a dangerous variable may be permitted for a single command or profile only by naming it explicitly, never via a wildcard.
Behaviour is consistent across Linux and macOS, with tests on both.
The second list (
keystore.rs) and theset_varspath are brought into line with the model.What would you like to see?
I would like dangerous environment variables to be managed through
policy.json, in the same way dangerous commands, paths, and credentials already are, rather than being hardcoded in the binary.Concretely:
The dangerous-variable set declared as policy data, modelled on the existing
dangerous_commandsgroup, so it can be reviewed, documented entry by entry, and extended without cutting a new release.A small core — the loader-injection variables and the secret-bearing tokens — kept compiled in as a floor that policy may extend but never remove or weaken, with nono refusing to start if the policy fails to load.
The model able to express whole name families (
LD_*,DYLD_*), to behave identically on Linux and macOS, and to account for the second list inkeystore.rsand the separateset_varspath.Optionally, a narrowly scoped, by-name exception for the rare command that genuinely needs an otherwise-dangerous variable — never through a wildcard.
In short: environment variables brought into line with every other category of risk — configured in policy, documented in the open, with a non-removable safety floor retained in code.
What have you tried instead?
No response
How is this blocking you?
Just an idea — low urgency
Additional context
No response