Skip to content

fix(windows): run scheduled task as logged-in user via /ru INTERACTIVE#91

Merged
ashishkurmi merged 3 commits into
step-security:mainfrom
swarit-stepsecurity:swarit/fix/windows-sys-schedule
May 21, 2026
Merged

fix(windows): run scheduled task as logged-in user via /ru INTERACTIVE#91
ashishkurmi merged 3 commits into
step-security:mainfrom
swarit-stepsecurity:swarit/fix/windows-sys-schedule

Conversation

@swarit-stepsecurity
Copy link
Copy Markdown
Member

What does this PR do?

Type of change

  • Bug fix
  • Enhancement
  • Documentation

Testing

  • Tested on macOS (version: ___)
  • Binary runs without errors: ./stepsecurity-dev-machine-guard --verbose
  • JSON output is valid: ./stepsecurity-dev-machine-guard --json | python3 -m json.tool
  • No secrets or credentials included
  • Lint passes: make lint
  • Tests pass: make test

Related Issues

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates the Windows scheduled task creation logic so that, when installed with admin privileges, the task is configured to run as the currently logged-in interactive user rather than as SYSTEM, aligning execution with user-scoped environment/data (HKCU, user profile, etc.).

Changes:

  • Change scheduled task /ru from SYSTEM to INTERACTIVE for admin installs.
  • Update unit test expectation to validate /ru INTERACTIVE.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
internal/schtasks/schtasks.go Switch admin task principal to INTERACTIVE and add explanatory inline comments.
internal/schtasks/schtasks_test.go Update tests to expect INTERACTIVE instead of SYSTEM.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

// HKCU, %USERPROFILE%, and PATH. /ru SYSTEM would run as
// NT AUTHORITY\SYSTEM, which can't see any of the user-scoped
// data the scanner depends on.
args = append(args, "/ru", "INTERACTIVE")
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good catch — addressed in 10f2422. After MkdirAll, when running as admin, we now run icacls to grant BUILTIN\Users (SID 545) Modify rights on the log dir with (OI)(CI) so files and subfolders inherit the permission. Verified on the Windows VM: C:\ProgramData\StepSecurity now shows an explicit BUILTIN\Users:(OI)(CI)(M) ACE alongside the inherited entries. A non-admin interactive user firing the task can now append to agent.log without Access Denied.

Comment thread internal/schtasks/schtasks.go Outdated
Comment on lines +104 to +106
// /ru INTERACTIVE binds the task to the BUILTIN\INTERACTIVE group
// (SID S-1-5-4) so it fires under the security context of whoever
// is interactively logged on at trigger time — picking up their
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Correct — fixed in 10f2422. Updated the comment to refer to NT AUTHORITY\INTERACTIVE (the actual well-known principal for SID S-1-5-4). BUILTIN domain SIDs are S-1-5-32-*, so the original wording was misleading.

…comment

The /ru INTERACTIVE scheduled task fires under whatever user is logged on
at trigger time, typically a non-admin developer. The default ACLs on
C:\ProgramData\StepSecurity (inherited from C:\ProgramData) only grant
non-admin users Read & Execute on existing files, so cmd.exe's `>>`
redirect to agent.log would fail with Access Denied — and a failed
redirect aborts the whole task action, so the periodic scan never runs.

Grant BUILTIN\Users (SID 545) Modify rights on the log dir after creating
it, propagated to files and subfolders, so any logged-in user can append.

Also corrects the /ru INTERACTIVE comment: SID S-1-5-4 is in the
NT AUTHORITY domain, not BUILTIN (BUILTIN\* SIDs are S-1-5-32-*).
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (2)

internal/schtasks/schtasks.go:54

  • icacls <dir> /grant ... updates the directory ACL but does not reliably propagate the new inheritable ACE to already-existing files (e.g., agent.log from a previous install). On upgrade, the task can still fail with Access Denied when appending to existing log files. Consider using icacls <dir> ... /T (or explicitly updating the log files) so upgrades also fix existing ACLs.
		_, _, _, icaclsErr := exec.Run(ctx, "icacls", logDir, "/grant", "*S-1-5-32-545:(OI)(CI)M", "/Q")

internal/schtasks/schtasks.go:54

  • Using icacls ... /grant on every install/upgrade can accumulate duplicate ACEs for the same SID over time. Prefer /grant:r (replace) to keep the ACL stable across repeated runs.
		_, _, _, icaclsErr := exec.Run(ctx, "icacls", logDir, "/grant", "*S-1-5-32-545:(OI)(CI)M", "/Q")

Comment on lines +54 to +56
_, _, _, icaclsErr := exec.Run(ctx, "icacls", logDir, "/grant", "*S-1-5-32-545:(OI)(CI)M", "/Q")
if icaclsErr != nil {
log.Warn("could not adjust log dir ACLs (%v) — non-admin users may not be able to write to %s", icaclsErr, logDir)
Comment on lines +45 to +58
// For admin installs the log dir lives at C:\ProgramData\StepSecurity, which
// inherits ACLs from C:\ProgramData and only grants non-admin users
// Read & Execute on the files inside. The /ru INTERACTIVE task fires under
// whatever user is logged on — typically a non-admin developer — and
// cmd.exe's `>>` redirect to agent.log would fail with Access Denied, which
// aborts the whole task action. Grant BUILTIN\Users (SID 545) Modify rights
// on the log dir, propagated to files and subfolders, so any logged-in
// user can append to the log files.
if exec.IsRoot() {
_, _, _, icaclsErr := exec.Run(ctx, "icacls", logDir, "/grant", "*S-1-5-32-545:(OI)(CI)M", "/Q")
if icaclsErr != nil {
log.Warn("could not adjust log dir ACLs (%v) — non-admin users may not be able to write to %s", icaclsErr, logDir)
}
}
@ashishkurmi ashishkurmi merged commit 09dc2a2 into step-security:main May 21, 2026
14 checks passed
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.

3 participants