Skip to content

[Core] Add get_safe_executable_path to prevent binary planting when spawning subprocess - #34212

Merged
Ethan Yang (necusjz) merged 4 commits into
Azure:devfrom
necusjz:safe-executable-solution
Oct 14, 2026
Merged

Ethan Yang (necusjz) merged 4 commits into
Azure:devfrom
necusjz:safe-executable-solution

Conversation

@necusjz

@necusjz Ethan Yang (necusjz) commented Oct 12, 2026 •

Copy link
Copy Markdown
Member

🤖 PR Validation — ️✔️ All clear

Breaking Changes Tests
️✔️ None ️✔️ 130/130

Related command

Description

it's developer-facing, so with hard brackets.

On Windows, starting a process by a bare name (e.g. cmd.exe, az) looks in the current working directory before the system directory and PATH. This happens with shell=False as well as shell=True. A malicious executable placed in a directory the user cds into (a cloned repo, an unzipped artifact) can then run inside the user's Azure CLI session (binary planting, CWE-427).

az upgrade was affected: after upgrading it runs az version and az extension update as subprocesses with the bare name az and shell=True.

This PR:

  1. Adds azure.cli.core.util.get_safe_executable_path(executable), a shared helper that turns an executable name into an absolute path using only trusted locations:

    • On Windows, %SystemRoot%\System32 and %SystemRoot% are searched first, so cmd.exe always comes from there.
    • Only absolute PATH entries are used. Empty and relative entries ("", ., bin) are skipped because they point into the current directory.
    • The current working directory is skipped. The comparison is by file identity, so differences in case, short names (PROGRA~1) or junctions don't get around it. A match whose symlink target is in the current directory is also rejected.
    • Windows PATHEXT extensions are tried, so az resolves to az.cmd/az.exe.
    • It returns None when there is no trusted match or the current directory can't be determined, the same contract as shutil.which. It never returns the bare name, because running that would bring back the current-directory lookup.
  2. Fixes az upgrade: the post-upgrade version check and the extension update calls now use absolute cmd.exe and az paths with shell=False. If either can't be found, it runs [sys.executable, '-m', 'azure.cli'] instead, which is also an absolute path.

  3. Docs: adds doc/secure_executable_invocation.md, a guide for module owners on finding and fixing bare executable calls (cmd.exe, docker, git, gh, kubectl, ...), and links it from doc/cli_subprocess_guidelines.md.

Testing Guide
Unit tests: TestSafeExecutablePath in src/azure-cli-core/azure/cli/core/tests/test_util.py. They cover the current directory on PATH, relative PATH entries, case-insensitive matching (Windows), skipping a fake binary to find the real one later on PATH, not found → None, an unknown current directory → None, and cmd.exe resolving to System32.

azdev test test_util --discover   # or: pytest src/azure-cli-core/azure/cli/core/tests/test_util.py -k TestSafeExecutablePath

Manual check (Windows):

mkdir C:\poc\proj; cd C:\poc\proj
# place a harmless az.cmd that writes a marker file, e.g.: echo pwned > C:\poc\PWNED.txt
az upgrade --yes
# Expected: the real CLI runs `version` / `extension update`; C:\poc\PWNED.txt is NOT created.

History Notes

[Component Name 1] BREAKING CHANGE: az command a: Make some customer-facing breaking change
[Component Name 2] az command b: Add some customer-facing feature


This checklist is used to make sure that common guidelines for a pull request are followed.

@yonzhan

Copy link
Copy Markdown
Collaborator

Core

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The fallback invocation and relative-path handling can still execute attacker-controlled code from the working directory.

3 open findings
What changed in this PR

Adds secure executable resolution to mitigate binary planting in subprocess calls.

Changes:

  • Adds and tests get_safe_executable_path.
  • Secures post-upgrade Azure CLI subprocess execution.
  • Documents secure executable invocation practices.
File Description
src/​azure-cli/​azure/​cli/​command_modules/​util/​custom.py Uses resolved executable paths during upgrades.
src/​azure-cli-core/​azure/​cli/​core/​util.py Implements safe executable resolution.
src/​azure-cli-core/​azure/​cli/​core/​tests/​test_util.py Adds resolver unit tests.
doc/​secure_executable_invocation.md Adds security guidance and examples.
doc/​cli_subprocess_guidelines.md Links the new guidance.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/azure-cli-core/azure/cli/core/util.py Outdated
Comment thread src/azure-cli/azure/cli/command_modules/util/custom.py
Comment thread doc/secure_executable_invocation.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Relative PYTHONPATH entries and the existing PIP upgrade path still permit current-directory module planting.

3 open findings
3 resolved since last review

🧠 Review effort: Balanced

Comment thread src/azure-cli-core/azure/cli/core/util.py Outdated
Comment thread src/azure-cli/azure/cli/command_modules/util/custom.py
Comment thread doc/cli_subprocess_guidelines.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Comment thread src/azure-cli-core/azure/cli/core/tests/test_util.py
Comment thread src/azure-cli-core/azure/cli/core/util.py Outdated
Comment thread doc/cli_subprocess_guidelines.md Outdated
Comment thread doc/secure_executable_invocation.md Outdated
Comment thread doc/secure_executable_invocation.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

CWD-relative paths, symlink targets, and the non-isolated interpreter fallback leave binary or module planting paths open.

2 open findings
4 resolved since last review

🧠 Review effort: Balanced

Comment thread src/azure-cli-core/azure/cli/core/util.py
@necusjz
Ethan Yang (necusjz) marked this pull request as ready for review October 13, 2026 07:52
@necusjz
Ethan Yang (necusjz) requested review from a team as code owners October 13, 2026 07:52
@necusjz
Ethan Yang (necusjz) merged commit 5f64a80 into Azure:dev Oct 14, 2026
52 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

act-platform-engineering-squad Auto-Assign Auto assign by bot Core CLI core infrastructure

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants