fix(agent): harden package broker caller identity - #1977
fix(agent): harden package broker caller identity#1977Benoît Cortier (CBenoit) wants to merge 10 commits into
Conversation
|
Implementation notes:
Validated with targeted default/development broker suites, retained crypt and ACL tests, the i686 broker check, nightly formatting, warnings-denied workspace Clippy, and the full workspace test suite. Note Human-tuned, LLM-assisted content. |
b627c9f to
71f7e67
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The new native structure size assertion references an unimported function and prevents compilation.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Hardens Windows package-broker authentication by retaining and validating client process, token, executable, and filesystem identities.
Changes:
- Adds retained-handle Authenticode and process-image verification.
- Pins trusted executable ancestors and enforces elevated Administrator identity.
- Bounds blocking identity capture and adds regression tests.
Prose verification was skipped because only Rust code and rustdoc changed.
File summaries
| File | Description |
|---|---|
crates/win-api-wrappers/src/undoc.rs |
Adds native process-image definitions. |
crates/win-api-wrappers/src/security/crypt.rs |
Verifies signatures through retained file handles. |
crates/win-api-wrappers/src/process.rs |
Adds image-mapping and process-instance checks. |
crates/now-package-broker/src/policy_security.rs |
Pins and validates executable ancestors. |
crates/now-package-broker/src/pipe.rs |
Moves identity capture to bounded blocking work. |
crates/now-package-broker/src/auth.rs |
Retains and authenticates client identity. |
crates/devolutions-agent-shared/src/windows/code_signing.rs |
Exposes retained-file signature validation. |
Review details
- Files reviewed: 7/7 changed files
- Comments generated: 1
- Review effort level: Balanced
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
🟡 Changes recommended
The trusted-writer requirement rejects the coordinated client’s default per-user installation, and one changed block fails repository formatting requirements.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 7/7 changed files
- Comments generated: 2
- Review effort level: Balanced
71f7e67 to
a0c3586
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The security bypass is broader than documented, and retained-path validation rejects supported no-drive-letter volumes.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (2)
crates/now-package-broker/src/auth.rs:85
skip_signature_validationis documented intask.rsand the Agent config as skipping only Authenticode validation, but using it asenforce_executable_securityalso disables the new DACL validation and ancestor pinning. In development-feature builds, this setting now removes a separate security control without saying so. Keep trusted-writer validation enabled, or introduce and document a separately named broad executable-security bypass.
let client = Self::from_process(
process_instance,
Arc::clone(&process),
!signature_validation_skipped(skip_signature_validation),
)?;
crates/now-package-broker/src/pipe.rs:84
- This new closure and its match arms are not rustfmt-formatted, unlike the surrounding control flow. Format the block before merging.
let capture = spawn_bounded_capture(permit, move || {
let client = PipeClient::from_connected_pipe(&server, skip_signature_validation);
(server, client)
});
let (_permit, server, client) = match capture.await {
- Files reviewed: 7/7 changed files
- Comments generated: 1
- Review effort level: Balanced
f35f57a to
4c42f92
Compare
4c42f92 to
92bd32a
Compare
There was a problem hiding this comment.
🔵 Needs a closer look
The security boundary depends on undocumented NT behavior and coordinated process, filesystem, token, and signature guarantees requiring final human validation.
Review details
- Files reviewed: 8/8 changed files
- Comments generated: 0 new
- Review effort level: Balanced
Retain the named-pipe connector process and reject recycled or exited process identities before authorizing requests. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Resolve the connector's kernel-backed main image, reject non-local image paths, and retain the exact mapped file object for subsequent authentication. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Verify Authenticode, trusted writers, and reparse-safe ancestors through the retained process-image file object so path swaps and writable images fail closed. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Run blocking caller-image checks outside the accept loop while retaining the connection permit until abandoned work actually completes. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep test-only process helpers out of production builds and accept expected fail-closed outcomes from locally modified WindowsApps security. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
State which handles establish identity, how capture is bounded, and which runtime and historical guarantees remain outside this layer. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep existing package-manager support for secured reparse-backed layouts while applying stricter retained ancestor pinning only to broker callers. Bind the WinGet regression to the resolved target and document the residual pre-capture identity interval. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep package-manager path compatibility and existing path-based signature behavior while applying retained handles, pinned ancestors, and full diagnostics only to broker callers. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep trusted-writer and ancestor validation active when only Authenticode is skipped, and support retained callers on local volume-GUID paths. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Run the LocalSystem policy tester from an atomically protected ProgramData leaf so production caller ACL checks remain enabled in CI. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
92bd32a to
f19fee3
Compare
There was a problem hiding this comment.
🔵 Needs a closer look
The security-sensitive design relies on undocumented Windows process APIs and cross-layer identity guarantees requiring final human validation.
Review details
- Files reviewed: 8/8 changed files
- Comments generated: 0 new
- Review effort level: Balanced
Retains the named-pipe client process and token identity, verifies that the retained executable object backs the process main image, and validates its Authenticode signature and trusted-writer path through retained handles.
Policy replacement independently requires the actual client token to be elevated with the built-in Administrators group enabled. Blocking identity capture remains bounded by the connection semaphore, while existing package-manager executable path compatibility is preserved.
This authenticates current process, image, and filesystem provenance after the initial process open. It does not attest runtime memory integrity, reconstruct historical ACL integrity, or close the interval before that initial process handle is acquired.
The change adds approximately 628 production lines and 543 inline test lines across seven files. Validator findings and readiness work inherited from the policy-write core remain tracked in #1975 and are intentionally not duplicated here.
Issue: #1937