Skip to content

Fix Environment variable exfiltration#702

Merged
hadarpl merged 1 commit into
mainfrom
fix_env_exfiltration
May 26, 2026
Merged

Fix Environment variable exfiltration#702
hadarpl merged 1 commit into
mainfrom
fix_env_exfiltration

Conversation

@hadarpl
Copy link
Copy Markdown
Collaborator

@hadarpl hadarpl commented May 19, 2026

Restrict ${env:...} expansion in --config-file to prevent env-var exfiltration
What
The external tag-group config (--config-file) supported ${env:NAME} expansion of any environment variable, with the expanded value written as a tag into IaC files. Combined with the bridgecrewio/yor-action auto-commit flow, anyone who could edit the config (e.g. via a PR when the file is versioned alongside the IaC) could have Yor read a runner environment variable and persist it into the repo. This MR locks that down.

Changes
src/common/tagging/external/tag_group.go — ${env:NAME} now only expands names matching an allowlist (YOR_* prefix, plus GIT_BRANCH for backward compatibility). A hard denylist (GITHUB_TOKEN, AWS_, anything containing SECRET / PASSWORD / API_KEY / CREDENTIAL, …) always wins. Refused expansions leave the literal ${env:NAME} in place and log a warning.
New env vars: YOR_ENV_ALLOWLIST (comma-separated, supports PREFIX
globs) to additively allow extra names, and YOR_DISABLE_ENV_EXPANSION=1 as a global kill switch.
src/common/tagging/external/env_expansion_test.go — unit tests for allowlist, denylist precedence, operator extension, kill switch, missing var, passthrough.
entrypoint.sh — refuses to auto-commit when --config-file resolves to a path inside the directory passed to -d; emits a GitHub Actions error and exits 2. Opt-out via commit_changes: 'NO' or by moving the config out.
docs/3.Custom Taggers/Custom_tagger_YAML.md + README.md — new "Security considerations for --config-file" section and a pointer next to the CLI example.
src/cloudformation/structure/cloudformation_parser.go, src/common/tagging/tag_group.go — unrelated one-line cleanups.
Why two layers
The Go-level allowlist protects every Yor invocation (CLI, pre-commit, third-party CI). The shell-level guard hardens the specific deployment where exploitation is amplified by an automatic push.

Breaking changes
${env:NAME} no longer expands arbitrary variables. Configs referencing names outside YOR_* / GIT_BRANCH will now write the literal ${env:NAME} as the tag value and log a warning. Migration: rename to a YOR_ prefix or add to YOR_ENV_ALLOWLIST. Names matching the credential denylist cannot be re-enabled — by design.
bridgecrewio/yor-action now exits 2 when --config-file lives inside the scanned directory and commit_changes is YES (default). Migration: move the config out of -d, or set commit_changes: 'NO'. Local CLI use and non-action CI are unaffected.
New environment variables consumed by Yor: YOR_ENV_ALLOWLIST, YOR_DISABLE_ENV_EXPANSION. Pre-existing variables with these names will now influence Yor's behavior.

for _, tag := range tags {
tag.Init()
tag.SetTagPrefix(t.Options.TagPrefix)
if !t.IsTagSkipped(tag) && (t.SpecifiedTags == nil || len(t.SpecifiedTags) == 0 || utils.InSlice(t.SpecifiedTags, strings.TrimPrefix(tag.GetKey(), t.Options.TagPrefix))) {
Copy link
Copy Markdown
Collaborator Author

@hadarpl hadarpl May 19, 2026

Choose a reason for hiding this comment

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

t.SpecifiedTags == nil || len(t.SpecifiedTags) == 0 collapses to just len(t.SpecifiedTags) == 0

This silence gosimple rule S1009 — "should omit nil check; len() for nil slices is defined as zero". A nil slice and an empty slice both report len() == 0, so the explicit != nil check is redundant and gosimple flags it.

}

resourceNames := make([]string, 0)
if template.Resources != nil && len(template.Resources) > 0 {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The template.Resources != nil guard was unnecessary because len(nil) is 0, so the > 0 comparison already filters out the nil case.

This silence gosimple rule S1009 — "should omit nil check; len() for nil slices is defined as zero". A nil slice and an empty slice both report len() == 0, so the explicit != nil check is redundant and gosimple flags it.

@hadarpl hadarpl merged commit d050fed into main May 26, 2026
6 of 7 checks passed
@hadarpl hadarpl deleted the fix_env_exfiltration branch May 26, 2026 11:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants