fix(security): use icacls /sid for locale-independent Windows ACL audit#38900
Conversation
On non-English Windows editions (Russian, Chinese, etc.) icacls prints account names in the system locale. When Node.js reads the output in a different code page the strings are garbled (e.g. "NT AUTHORITY\???????" for "NT AUTHORITY\СИСТЕМА"), causing summarizeWindowsAcl to classify SYSTEM and Administrators as untrusted and flag the config files as "others writable" — a false-positive security alert. Fix: 1. Pass /sid to icacls so it outputs security identifiers (*S-1-5-X-...) instead of locale-dependent account names. 2. Extend SID_RE to accept the leading * that icacls prepends to SIDs in /sid mode: /^\*?s-\d+-\d+(-\d+)+$/i 3. Strip the * before looking up the bare SID in TRUSTED_SIDS / the per-user USERSID set so *S-1-5-18 is correctly classified as SYSTEM (trusted) and *S-1-5-32-544 as Administrators (trusted). Tests: - Update the inspectWindowsAcl "returns parsed ACL entries" assertion to expect the /sid flag in the icacls call. - Add "classifies *S-1-5-18 (icacls /sid prefix form of SYSTEM) as trusted" SID classification test. - Add "classifies *S-1-5-32-544 (icacls /sid Administrators) as trusted". - Add inspectWindowsAcl end-to-end test with /sid-format mock output (*S-1-5-18, *S-1-5-32-544, user SID) — all three classified as trusted. Fixes openclaw#35834
…cacls /sid When icacls is invoked with /sid, world-equivalent principals like Everyone, Authenticated Users, and BUILTIN\Users are emitted as raw SIDs (*S-1-1-0, *S-1-5-11, *S-1-5-32-545). classifyPrincipal() had no SID-based mapping for these, so they fell through to the generic 'group' category instead of 'world', silently downgrading security findings that should trigger world-write/world-readable alerts. Fix: add a WORLD_SIDS constant and check it before falling back to 'group'. Add three regression tests to lock in the behaviour.
Greptile SummaryThis PR fixes a real locale-dependence bug in the Windows ACL auditor by switching Notable issue:
Confidence Score: 4/5
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cd05349815
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| // Windows (Russian, Chinese, etc.) where icacls prints Cyrillic / CJK | ||
| // characters that may be garbled when Node reads them in the wrong code | ||
| // page. Fixes #35834. | ||
| const { stdout, stderr } = await exec("icacls", [targetPath, "/sid"]); |
There was a problem hiding this comment.
Keep caller ACE trusted when enabling icacls SID mode
Switching inspectWindowsAcl to icacls ... /sid makes the caller's ACE arrive as a SID, but the trust set only includes a caller SID when env.USERSID is populated; in normal audit execution we pass process.env and do not populate USERSID, so the owner entry is reclassified as untrustedGroup and secure paths can be falsely flagged as group-readable/writable. Please add a non-USERSID fallback for resolving the current user SID (or a non-SID fallback path) before forcing SID-only output.
Useful? React with 👍 / 👎.
📝 PR Review Fix - Windows ACL SID ModeHi @byungsker! Excellent work on fixing the locale-independent Windows ACL audit using 🔴 Critical IssueCaller ACE Classification Fails Without USERSIDLocation: Problem: function buildTrustedPrincipals(env?: NodeJS.ProcessEnv): Set<string> {
const trusted = new Set<string>(TRUSTED_BASE);
const principal = resolveWindowsUserPrincipal(env);
if (principal) {
trusted.add(normalize(principal));
// ... adds username variants
}
const userSid = normalize(env?.USERSID ?? "");
if (userSid && SID_RE.test(userSid)) {
trusted.add(userSid); // ❌ Only trusts SID if USERSID env var exists
}
return trusted;
}Impact:
Example scenario: // Normal call - USERSID not set
const result = await inspectWindowsAcl("C:\\secret", { env: process.env });
// icacls /sid output includes:
// *S-1-5-21-...-1001:(OI)(CI)(F) // Caller's SID
// But buildTrustedPrincipals only trusts:
// - TRUSTED_BASE (SYSTEM, Administrators)
// - Username variants (DOMAIN\user, user)
// - NOT the caller's SID (because USERSID env var is missing)
// Result: caller's ACE classified as "untrustedGroup" ❌✅ Suggested FixAdd a fallback mechanism to resolve the current user's SID when Option 1: Use
|
mdlmarkham
left a comment
There was a problem hiding this comment.
Review: Locale-Independent Windows ACL Audit ✅
Verdict: Critical fix for non-English Windows. Ready to merge.
The Bug
On non-English Windows (Russian, German, CJK), icacls outputs localized account names:
СИСТЕМАinstead ofSYSTEMВСЕinstead ofEveryone
Node.js may garble multi-byte characters, causing the security auditor to misclassify SYSTEM as unknown/untrusted → false-positive alerts.
The Fix
Pass /sid to icacls to output canonical ASCII SIDs:
*S-1-5-18instead ofСИСТЕМА(SYSTEM)*S-1-1-0instead ofВсе(Everyone)
Then classify by SID, not by localized name.
Key Changes
SID_RE— Accept optional leading*from/sidoutputclassifyPrincipal()— Strip*prefix, lookup SID in known tablesWORLD_SIDS— New constant for world-equivalent SIDs:S-1-1-0(Everyone)S-1-5-11(Authenticated Users)S-1-5-32-545(BUILTIN\Users)
formatIcaclsResetCommand()— Use*S-1-5-18instead of localized name
Test Coverage
Comprehensive:
- ✅
*S-1-5-18(SYSTEM SID) → trusted - ✅
*S-1-5-32-544(Administrators SID) → trusted - ✅
*S-1-1-0(Everyone) → world (not group) - ✅
*S-1-5-11(Authenticated Users) → world - ✅
*S-1-5-32-545(BUILTIN\Users) → world - ✅ Full mock with
/sidoutput - ✅ CI: 29/29 checks pass
Security Impact
Before: Non-English Windows → false positives → operators learn to ignore security alerts
After: Correct classification → real issues get attention
This is a security reliability fix — reduces alert fatigue.
Edge Cases
- Mixed output (some names, some SIDs):
icacls /sidoutputs all SIDs ✅ - Third-party SIDs not in table: Fall through to
groupclassification ✅ - Domain SIDs: Not in table, classified by prefix matching
Recommendation: Approve. Critical for international users, well-tested, follows SID best practices.
🔒 Aisle Security AnalysisWe found 1 potential security issue(s) in this PR:
1. 🟠 Uncontrolled search path execution of
|
| Property | Value |
|---|---|
| Severity | High |
| CWE | CWE-427 |
| Location | src/security/windows-acl.ts:270-304 |
Description
The new fallback in inspectWindowsAcl() resolves the current user SID by executing whoami by name when USERSID is missing.
runExec("whoami", ...)relies on Windows executable resolution (current directory/PATH search).- If an attacker can influence the working directory or
PATH(e.g., running the tool inside an untrusted repo directory containing a maliciouswhoami.exe), the process may execute the attacker-controlled binary. - The resulting (spoofed) SID is then trusted as
USERSID, which can downgrade findings by reclassifying matching SID ACL entries fromuntrustedGrouptotrusted.
Vulnerable code:
const { stdout, stderr } = await exec("whoami", ["/user", "/fo", "csv", "/nh"]);
const match = `${stdout}\n${stderr}`.match(/\*?S-\d+-\d+(?:-\d+)+/i);
...
effectiveEnv = { ...effectiveEnv, USERSID: currentUserSid };Recommendation
Avoid PATH/current-directory resolution for OS binaries and tighten SID extraction.
- Execute
whoami.exevia an absolute, trusted path (e.g., System32) rather than relying on search-path resolution. - Strictly parse the expected CSV output and validate:
- exactly 2 columns
- the SID column matches
SID_RE(anchored) - optionally the username column matches the expected current user principal
Example:
import path from "node:path";
function system32Bin(name: string): string {
// Prefer a constant base; env vars can be influenced.
const windir = process.env.WINDIR || "C:\\Windows";
return path.join(windir, "System32", `${name}.exe`);
}
async function resolveCurrentUserSid(exec: ExecFn): Promise<string | null> {
const whoamiPath = system32Bin("whoami");
const { stdout } = await exec(whoamiPath, ["/user", "/fo", "csv", "/nh"]);
const line = stdout.trim().split(/\r?\n/)[0] ?? "";
// Minimal CSV handling for two quoted fields: "user","SID"
const m = line.match(/^\s*"[^"]+"\s*,\s*"(\*?s-\d+-\d+(?:-\d+)+)"\s*$/i);
return m ? normalizeSid(m[1]) : null;
}This prevents binary-hijacking and reduces the chance of trusting an unintended SID.
Analyzed PR: #38900 at commit 378ff5b
Last updated on: 2026-03-07T17:59:51Z
|
Pushed a follow-up fix on top of this branch. The SID-based approach is still the right canonical path for #35834, but it needed one more piece: when It also keeps well-known world SIDs ( Local verification:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 378ff5b1f6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (TRUSTED_SIDS.has(sid) || trustedPrincipals.has(sid)) { | ||
| return "trusted"; | ||
| } | ||
| return "group"; |
There was a problem hiding this comment.
Trust Creator Owner SID in SID-based ACL classification
After switching inspectWindowsAcl to icacls /sid, ACL entries like CREATOR OWNER are emitted as *S-1-3-0, but the SID path in classifyPrincipal only trusts TRUSTED_SIDS and caller SID, so S-1-3-0 now falls through to group. On default Windows directory ACLs that include CREATOR OWNER:(OI)(CI)(IO)(F), this produces false untrusted group-writable findings even though this principal was previously trusted by name.
Useful? React with 👍 / 👎.
* origin/main: (37 commits) chore: land #39056 Node version hint sync (thanks @onstash) fix(security): use icacls /sid for locale-independent Windows ACL audit (#38900) fix(ci): refresh detect-secrets baseline offsets fix(security): strip custom auth headers on cross-origin redirects fix(ci): harden diffs viewer request guard and secret scan baseline Secrets: harden SecretRef-safe models.json persistence (#38955) docs(changelog): credit allowlist scoping report refactor(commands): dedupe onboard search perplexity test setup refactor(commands): dedupe message command secret-config tests refactor(cli): dedupe restart health probe setup tests refactor(cron): dedupe interim retry fallback assertions refactor(commands): dedupe model probe target test fixtures refactor(discord): dedupe message preflight test runners refactor(discord): share message handler test scaffolding refactor(discord): dedupe native command ACP routing test setup refactor(slack): dedupe app mention in-flight race setup refactor(slack): reuse shared prepare test scaffolding refactor(plugin-sdk): extract shared channel prelude exports refactor(slack): dedupe app mention race test setup refactor(line): dedupe replay webhook test fixtures ... # Conflicts: # .secrets.baseline # apps/ios/fastlane/Fastfile # src/commands/message.test.ts
…it (openclaw#38900) * fix(security): use icacls /sid for locale-independent Windows ACL audit On non-English Windows editions (Russian, Chinese, etc.) icacls prints account names in the system locale. When Node.js reads the output in a different code page the strings are garbled (e.g. "NT AUTHORITY\???????" for "NT AUTHORITY\СИСТЕМА"), causing summarizeWindowsAcl to classify SYSTEM and Administrators as untrusted and flag the config files as "others writable" — a false-positive security alert. Fix: 1. Pass /sid to icacls so it outputs security identifiers (*S-1-5-X-...) instead of locale-dependent account names. 2. Extend SID_RE to accept the leading * that icacls prepends to SIDs in /sid mode: /^\*?s-\d+-\d+(-\d+)+$/i 3. Strip the * before looking up the bare SID in TRUSTED_SIDS / the per-user USERSID set so *S-1-5-18 is correctly classified as SYSTEM (trusted) and *S-1-5-32-544 as Administrators (trusted). Tests: - Update the inspectWindowsAcl "returns parsed ACL entries" assertion to expect the /sid flag in the icacls call. - Add "classifies *S-1-5-18 (icacls /sid prefix form of SYSTEM) as trusted" SID classification test. - Add "classifies *S-1-5-32-544 (icacls /sid Administrators) as trusted". - Add inspectWindowsAcl end-to-end test with /sid-format mock output (*S-1-5-18, *S-1-5-32-544, user SID) — all three classified as trusted. Fixes openclaw#35834 * fix(security): classify world-equivalent SIDs as 'world' when using icacls /sid When icacls is invoked with /sid, world-equivalent principals like Everyone, Authenticated Users, and BUILTIN\Users are emitted as raw SIDs (*S-1-1-0, *S-1-5-11, *S-1-5-32-545). classifyPrincipal() had no SID-based mapping for these, so they fell through to the generic 'group' category instead of 'world', silently downgrading security findings that should trigger world-write/world-readable alerts. Fix: add a WORLD_SIDS constant and check it before falling back to 'group'. Add three regression tests to lock in the behaviour. * Security: resolve owner SID fallback for Windows ACL audit --------- Co-authored-by: Vincent Koc <[email protected]>
…it (openclaw#38900) * fix(security): use icacls /sid for locale-independent Windows ACL audit On non-English Windows editions (Russian, Chinese, etc.) icacls prints account names in the system locale. When Node.js reads the output in a different code page the strings are garbled (e.g. "NT AUTHORITY\???????" for "NT AUTHORITY\СИСТЕМА"), causing summarizeWindowsAcl to classify SYSTEM and Administrators as untrusted and flag the config files as "others writable" — a false-positive security alert. Fix: 1. Pass /sid to icacls so it outputs security identifiers (*S-1-5-X-...) instead of locale-dependent account names. 2. Extend SID_RE to accept the leading * that icacls prepends to SIDs in /sid mode: /^\*?s-\d+-\d+(-\d+)+$/i 3. Strip the * before looking up the bare SID in TRUSTED_SIDS / the per-user USERSID set so *S-1-5-18 is correctly classified as SYSTEM (trusted) and *S-1-5-32-544 as Administrators (trusted). Tests: - Update the inspectWindowsAcl "returns parsed ACL entries" assertion to expect the /sid flag in the icacls call. - Add "classifies *S-1-5-18 (icacls /sid prefix form of SYSTEM) as trusted" SID classification test. - Add "classifies *S-1-5-32-544 (icacls /sid Administrators) as trusted". - Add inspectWindowsAcl end-to-end test with /sid-format mock output (*S-1-5-18, *S-1-5-32-544, user SID) — all three classified as trusted. Fixes openclaw#35834 * fix(security): classify world-equivalent SIDs as 'world' when using icacls /sid When icacls is invoked with /sid, world-equivalent principals like Everyone, Authenticated Users, and BUILTIN\Users are emitted as raw SIDs (*S-1-1-0, *S-1-5-11, *S-1-5-32-545). classifyPrincipal() had no SID-based mapping for these, so they fell through to the generic 'group' category instead of 'world', silently downgrading security findings that should trigger world-write/world-readable alerts. Fix: add a WORLD_SIDS constant and check it before falling back to 'group'. Add three regression tests to lock in the behaviour. * Security: resolve owner SID fallback for Windows ACL audit --------- Co-authored-by: Vincent Koc <[email protected]>
…it (openclaw#38900) * fix(security): use icacls /sid for locale-independent Windows ACL audit On non-English Windows editions (Russian, Chinese, etc.) icacls prints account names in the system locale. When Node.js reads the output in a different code page the strings are garbled (e.g. "NT AUTHORITY\???????" for "NT AUTHORITY\СИСТЕМА"), causing summarizeWindowsAcl to classify SYSTEM and Administrators as untrusted and flag the config files as "others writable" — a false-positive security alert. Fix: 1. Pass /sid to icacls so it outputs security identifiers (*S-1-5-X-...) instead of locale-dependent account names. 2. Extend SID_RE to accept the leading * that icacls prepends to SIDs in /sid mode: /^\*?s-\d+-\d+(-\d+)+$/i 3. Strip the * before looking up the bare SID in TRUSTED_SIDS / the per-user USERSID set so *S-1-5-18 is correctly classified as SYSTEM (trusted) and *S-1-5-32-544 as Administrators (trusted). Tests: - Update the inspectWindowsAcl "returns parsed ACL entries" assertion to expect the /sid flag in the icacls call. - Add "classifies *S-1-5-18 (icacls /sid prefix form of SYSTEM) as trusted" SID classification test. - Add "classifies *S-1-5-32-544 (icacls /sid Administrators) as trusted". - Add inspectWindowsAcl end-to-end test with /sid-format mock output (*S-1-5-18, *S-1-5-32-544, user SID) — all three classified as trusted. Fixes openclaw#35834 * fix(security): classify world-equivalent SIDs as 'world' when using icacls /sid When icacls is invoked with /sid, world-equivalent principals like Everyone, Authenticated Users, and BUILTIN\Users are emitted as raw SIDs (*S-1-1-0, *S-1-5-11, *S-1-5-32-545). classifyPrincipal() had no SID-based mapping for these, so they fell through to the generic 'group' category instead of 'world', silently downgrading security findings that should trigger world-write/world-readable alerts. Fix: add a WORLD_SIDS constant and check it before falling back to 'group'. Add three regression tests to lock in the behaviour. * Security: resolve owner SID fallback for Windows ACL audit --------- Co-authored-by: Vincent Koc <[email protected]>
…it (openclaw#38900) * fix(security): use icacls /sid for locale-independent Windows ACL audit On non-English Windows editions (Russian, Chinese, etc.) icacls prints account names in the system locale. When Node.js reads the output in a different code page the strings are garbled (e.g. "NT AUTHORITY\???????" for "NT AUTHORITY\СИСТЕМА"), causing summarizeWindowsAcl to classify SYSTEM and Administrators as untrusted and flag the config files as "others writable" — a false-positive security alert. Fix: 1. Pass /sid to icacls so it outputs security identifiers (*S-1-5-X-...) instead of locale-dependent account names. 2. Extend SID_RE to accept the leading * that icacls prepends to SIDs in /sid mode: /^\*?s-\d+-\d+(-\d+)+$/i 3. Strip the * before looking up the bare SID in TRUSTED_SIDS / the per-user USERSID set so *S-1-5-18 is correctly classified as SYSTEM (trusted) and *S-1-5-32-544 as Administrators (trusted). Tests: - Update the inspectWindowsAcl "returns parsed ACL entries" assertion to expect the /sid flag in the icacls call. - Add "classifies *S-1-5-18 (icacls /sid prefix form of SYSTEM) as trusted" SID classification test. - Add "classifies *S-1-5-32-544 (icacls /sid Administrators) as trusted". - Add inspectWindowsAcl end-to-end test with /sid-format mock output (*S-1-5-18, *S-1-5-32-544, user SID) — all three classified as trusted. Fixes openclaw#35834 * fix(security): classify world-equivalent SIDs as 'world' when using icacls /sid When icacls is invoked with /sid, world-equivalent principals like Everyone, Authenticated Users, and BUILTIN\Users are emitted as raw SIDs (*S-1-1-0, *S-1-5-11, *S-1-5-32-545). classifyPrincipal() had no SID-based mapping for these, so they fell through to the generic 'group' category instead of 'world', silently downgrading security findings that should trigger world-write/world-readable alerts. Fix: add a WORLD_SIDS constant and check it before falling back to 'group'. Add three regression tests to lock in the behaviour. * Security: resolve owner SID fallback for Windows ACL audit --------- Co-authored-by: Vincent Koc <[email protected]>
…it (openclaw#38900) * fix(security): use icacls /sid for locale-independent Windows ACL audit On non-English Windows editions (Russian, Chinese, etc.) icacls prints account names in the system locale. When Node.js reads the output in a different code page the strings are garbled (e.g. "NT AUTHORITY\???????" for "NT AUTHORITY\СИСТЕМА"), causing summarizeWindowsAcl to classify SYSTEM and Administrators as untrusted and flag the config files as "others writable" — a false-positive security alert. Fix: 1. Pass /sid to icacls so it outputs security identifiers (*S-1-5-X-...) instead of locale-dependent account names. 2. Extend SID_RE to accept the leading * that icacls prepends to SIDs in /sid mode: /^\*?s-\d+-\d+(-\d+)+$/i 3. Strip the * before looking up the bare SID in TRUSTED_SIDS / the per-user USERSID set so *S-1-5-18 is correctly classified as SYSTEM (trusted) and *S-1-5-32-544 as Administrators (trusted). Tests: - Update the inspectWindowsAcl "returns parsed ACL entries" assertion to expect the /sid flag in the icacls call. - Add "classifies *S-1-5-18 (icacls /sid prefix form of SYSTEM) as trusted" SID classification test. - Add "classifies *S-1-5-32-544 (icacls /sid Administrators) as trusted". - Add inspectWindowsAcl end-to-end test with /sid-format mock output (*S-1-5-18, *S-1-5-32-544, user SID) — all three classified as trusted. Fixes openclaw#35834 * fix(security): classify world-equivalent SIDs as 'world' when using icacls /sid When icacls is invoked with /sid, world-equivalent principals like Everyone, Authenticated Users, and BUILTIN\Users are emitted as raw SIDs (*S-1-1-0, *S-1-5-11, *S-1-5-32-545). classifyPrincipal() had no SID-based mapping for these, so they fell through to the generic 'group' category instead of 'world', silently downgrading security findings that should trigger world-write/world-readable alerts. Fix: add a WORLD_SIDS constant and check it before falling back to 'group'. Add three regression tests to lock in the behaviour. * Security: resolve owner SID fallback for Windows ACL audit --------- Co-authored-by: Vincent Koc <[email protected]>
…it (openclaw#38900) * fix(security): use icacls /sid for locale-independent Windows ACL audit On non-English Windows editions (Russian, Chinese, etc.) icacls prints account names in the system locale. When Node.js reads the output in a different code page the strings are garbled (e.g. "NT AUTHORITY\???????" for "NT AUTHORITY\СИСТЕМА"), causing summarizeWindowsAcl to classify SYSTEM and Administrators as untrusted and flag the config files as "others writable" — a false-positive security alert. Fix: 1. Pass /sid to icacls so it outputs security identifiers (*S-1-5-X-...) instead of locale-dependent account names. 2. Extend SID_RE to accept the leading * that icacls prepends to SIDs in /sid mode: /^\*?s-\d+-\d+(-\d+)+$/i 3. Strip the * before looking up the bare SID in TRUSTED_SIDS / the per-user USERSID set so *S-1-5-18 is correctly classified as SYSTEM (trusted) and *S-1-5-32-544 as Administrators (trusted). Tests: - Update the inspectWindowsAcl "returns parsed ACL entries" assertion to expect the /sid flag in the icacls call. - Add "classifies *S-1-5-18 (icacls /sid prefix form of SYSTEM) as trusted" SID classification test. - Add "classifies *S-1-5-32-544 (icacls /sid Administrators) as trusted". - Add inspectWindowsAcl end-to-end test with /sid-format mock output (*S-1-5-18, *S-1-5-32-544, user SID) — all three classified as trusted. Fixes openclaw#35834 * fix(security): classify world-equivalent SIDs as 'world' when using icacls /sid When icacls is invoked with /sid, world-equivalent principals like Everyone, Authenticated Users, and BUILTIN\Users are emitted as raw SIDs (*S-1-1-0, *S-1-5-11, *S-1-5-32-545). classifyPrincipal() had no SID-based mapping for these, so they fell through to the generic 'group' category instead of 'world', silently downgrading security findings that should trigger world-write/world-readable alerts. Fix: add a WORLD_SIDS constant and check it before falling back to 'group'. Add three regression tests to lock in the behaviour. * Security: resolve owner SID fallback for Windows ACL audit --------- Co-authored-by: Vincent Koc <[email protected]>
…it (openclaw#38900) * fix(security): use icacls /sid for locale-independent Windows ACL audit On non-English Windows editions (Russian, Chinese, etc.) icacls prints account names in the system locale. When Node.js reads the output in a different code page the strings are garbled (e.g. "NT AUTHORITY\???????" for "NT AUTHORITY\СИСТЕМА"), causing summarizeWindowsAcl to classify SYSTEM and Administrators as untrusted and flag the config files as "others writable" — a false-positive security alert. Fix: 1. Pass /sid to icacls so it outputs security identifiers (*S-1-5-X-...) instead of locale-dependent account names. 2. Extend SID_RE to accept the leading * that icacls prepends to SIDs in /sid mode: /^\*?s-\d+-\d+(-\d+)+$/i 3. Strip the * before looking up the bare SID in TRUSTED_SIDS / the per-user USERSID set so *S-1-5-18 is correctly classified as SYSTEM (trusted) and *S-1-5-32-544 as Administrators (trusted). Tests: - Update the inspectWindowsAcl "returns parsed ACL entries" assertion to expect the /sid flag in the icacls call. - Add "classifies *S-1-5-18 (icacls /sid prefix form of SYSTEM) as trusted" SID classification test. - Add "classifies *S-1-5-32-544 (icacls /sid Administrators) as trusted". - Add inspectWindowsAcl end-to-end test with /sid-format mock output (*S-1-5-18, *S-1-5-32-544, user SID) — all three classified as trusted. Fixes openclaw#35834 * fix(security): classify world-equivalent SIDs as 'world' when using icacls /sid When icacls is invoked with /sid, world-equivalent principals like Everyone, Authenticated Users, and BUILTIN\Users are emitted as raw SIDs (*S-1-1-0, *S-1-5-11, *S-1-5-32-545). classifyPrincipal() had no SID-based mapping for these, so they fell through to the generic 'group' category instead of 'world', silently downgrading security findings that should trigger world-write/world-readable alerts. Fix: add a WORLD_SIDS constant and check it before falling back to 'group'. Add three regression tests to lock in the behaviour. * Security: resolve owner SID fallback for Windows ACL audit --------- Co-authored-by: Vincent Koc <[email protected]>
…it (openclaw#38900) * fix(security): use icacls /sid for locale-independent Windows ACL audit On non-English Windows editions (Russian, Chinese, etc.) icacls prints account names in the system locale. When Node.js reads the output in a different code page the strings are garbled (e.g. "NT AUTHORITY\???????" for "NT AUTHORITY\СИСТЕМА"), causing summarizeWindowsAcl to classify SYSTEM and Administrators as untrusted and flag the config files as "others writable" — a false-positive security alert. Fix: 1. Pass /sid to icacls so it outputs security identifiers (*S-1-5-X-...) instead of locale-dependent account names. 2. Extend SID_RE to accept the leading * that icacls prepends to SIDs in /sid mode: /^\*?s-\d+-\d+(-\d+)+$/i 3. Strip the * before looking up the bare SID in TRUSTED_SIDS / the per-user USERSID set so *S-1-5-18 is correctly classified as SYSTEM (trusted) and *S-1-5-32-544 as Administrators (trusted). Tests: - Update the inspectWindowsAcl "returns parsed ACL entries" assertion to expect the /sid flag in the icacls call. - Add "classifies *S-1-5-18 (icacls /sid prefix form of SYSTEM) as trusted" SID classification test. - Add "classifies *S-1-5-32-544 (icacls /sid Administrators) as trusted". - Add inspectWindowsAcl end-to-end test with /sid-format mock output (*S-1-5-18, *S-1-5-32-544, user SID) — all three classified as trusted. Fixes openclaw#35834 * fix(security): classify world-equivalent SIDs as 'world' when using icacls /sid When icacls is invoked with /sid, world-equivalent principals like Everyone, Authenticated Users, and BUILTIN\Users are emitted as raw SIDs (*S-1-1-0, *S-1-5-11, *S-1-5-32-545). classifyPrincipal() had no SID-based mapping for these, so they fell through to the generic 'group' category instead of 'world', silently downgrading security findings that should trigger world-write/world-readable alerts. Fix: add a WORLD_SIDS constant and check it before falling back to 'group'. Add three regression tests to lock in the behaviour. * Security: resolve owner SID fallback for Windows ACL audit --------- Co-authored-by: Vincent Koc <[email protected]>
…it (openclaw#38900) * fix(security): use icacls /sid for locale-independent Windows ACL audit On non-English Windows editions (Russian, Chinese, etc.) icacls prints account names in the system locale. When Node.js reads the output in a different code page the strings are garbled (e.g. "NT AUTHORITY\???????" for "NT AUTHORITY\СИСТЕМА"), causing summarizeWindowsAcl to classify SYSTEM and Administrators as untrusted and flag the config files as "others writable" — a false-positive security alert. Fix: 1. Pass /sid to icacls so it outputs security identifiers (*S-1-5-X-...) instead of locale-dependent account names. 2. Extend SID_RE to accept the leading * that icacls prepends to SIDs in /sid mode: /^\*?s-\d+-\d+(-\d+)+$/i 3. Strip the * before looking up the bare SID in TRUSTED_SIDS / the per-user USERSID set so *S-1-5-18 is correctly classified as SYSTEM (trusted) and *S-1-5-32-544 as Administrators (trusted). Tests: - Update the inspectWindowsAcl "returns parsed ACL entries" assertion to expect the /sid flag in the icacls call. - Add "classifies *S-1-5-18 (icacls /sid prefix form of SYSTEM) as trusted" SID classification test. - Add "classifies *S-1-5-32-544 (icacls /sid Administrators) as trusted". - Add inspectWindowsAcl end-to-end test with /sid-format mock output (*S-1-5-18, *S-1-5-32-544, user SID) — all three classified as trusted. Fixes openclaw#35834 * fix(security): classify world-equivalent SIDs as 'world' when using icacls /sid When icacls is invoked with /sid, world-equivalent principals like Everyone, Authenticated Users, and BUILTIN\Users are emitted as raw SIDs (*S-1-1-0, *S-1-5-11, *S-1-5-32-545). classifyPrincipal() had no SID-based mapping for these, so they fell through to the generic 'group' category instead of 'world', silently downgrading security findings that should trigger world-write/world-readable alerts. Fix: add a WORLD_SIDS constant and check it before falling back to 'group'. Add three regression tests to lock in the behaviour. * Security: resolve owner SID fallback for Windows ACL audit --------- Co-authored-by: Vincent Koc <[email protected]>
…it (openclaw#38900) * fix(security): use icacls /sid for locale-independent Windows ACL audit On non-English Windows editions (Russian, Chinese, etc.) icacls prints account names in the system locale. When Node.js reads the output in a different code page the strings are garbled (e.g. "NT AUTHORITY\???????" for "NT AUTHORITY\СИСТЕМА"), causing summarizeWindowsAcl to classify SYSTEM and Administrators as untrusted and flag the config files as "others writable" — a false-positive security alert. Fix: 1. Pass /sid to icacls so it outputs security identifiers (*S-1-5-X-...) instead of locale-dependent account names. 2. Extend SID_RE to accept the leading * that icacls prepends to SIDs in /sid mode: /^\*?s-\d+-\d+(-\d+)+$/i 3. Strip the * before looking up the bare SID in TRUSTED_SIDS / the per-user USERSID set so *S-1-5-18 is correctly classified as SYSTEM (trusted) and *S-1-5-32-544 as Administrators (trusted). Tests: - Update the inspectWindowsAcl "returns parsed ACL entries" assertion to expect the /sid flag in the icacls call. - Add "classifies *S-1-5-18 (icacls /sid prefix form of SYSTEM) as trusted" SID classification test. - Add "classifies *S-1-5-32-544 (icacls /sid Administrators) as trusted". - Add inspectWindowsAcl end-to-end test with /sid-format mock output (*S-1-5-18, *S-1-5-32-544, user SID) — all three classified as trusted. Fixes openclaw#35834 * fix(security): classify world-equivalent SIDs as 'world' when using icacls /sid When icacls is invoked with /sid, world-equivalent principals like Everyone, Authenticated Users, and BUILTIN\Users are emitted as raw SIDs (*S-1-1-0, *S-1-5-11, *S-1-5-32-545). classifyPrincipal() had no SID-based mapping for these, so they fell through to the generic 'group' category instead of 'world', silently downgrading security findings that should trigger world-write/world-readable alerts. Fix: add a WORLD_SIDS constant and check it before falling back to 'group'. Add three regression tests to lock in the behaviour. * Security: resolve owner SID fallback for Windows ACL audit --------- Co-authored-by: Vincent Koc <[email protected]> (cherry picked from commit 7735a0b)
…it (openclaw#38900) * fix(security): use icacls /sid for locale-independent Windows ACL audit On non-English Windows editions (Russian, Chinese, etc.) icacls prints account names in the system locale. When Node.js reads the output in a different code page the strings are garbled (e.g. "NT AUTHORITY\???????" for "NT AUTHORITY\СИСТЕМА"), causing summarizeWindowsAcl to classify SYSTEM and Administrators as untrusted and flag the config files as "others writable" — a false-positive security alert. Fix: 1. Pass /sid to icacls so it outputs security identifiers (*S-1-5-X-...) instead of locale-dependent account names. 2. Extend SID_RE to accept the leading * that icacls prepends to SIDs in /sid mode: /^\*?s-\d+-\d+(-\d+)+$/i 3. Strip the * before looking up the bare SID in TRUSTED_SIDS / the per-user USERSID set so *S-1-5-18 is correctly classified as SYSTEM (trusted) and *S-1-5-32-544 as Administrators (trusted). Tests: - Update the inspectWindowsAcl "returns parsed ACL entries" assertion to expect the /sid flag in the icacls call. - Add "classifies *S-1-5-18 (icacls /sid prefix form of SYSTEM) as trusted" SID classification test. - Add "classifies *S-1-5-32-544 (icacls /sid Administrators) as trusted". - Add inspectWindowsAcl end-to-end test with /sid-format mock output (*S-1-5-18, *S-1-5-32-544, user SID) — all three classified as trusted. Fixes openclaw#35834 * fix(security): classify world-equivalent SIDs as 'world' when using icacls /sid When icacls is invoked with /sid, world-equivalent principals like Everyone, Authenticated Users, and BUILTIN\Users are emitted as raw SIDs (*S-1-1-0, *S-1-5-11, *S-1-5-32-545). classifyPrincipal() had no SID-based mapping for these, so they fell through to the generic 'group' category instead of 'world', silently downgrading security findings that should trigger world-write/world-readable alerts. Fix: add a WORLD_SIDS constant and check it before falling back to 'group'. Add three regression tests to lock in the behaviour. * Security: resolve owner SID fallback for Windows ACL audit --------- Co-authored-by: Vincent Koc <[email protected]> (cherry picked from commit 7735a0b)
Problem
On Windows machines with non-English locales (Russian, German, French, Spanish, CJK),
icaclsprints account names in the system locale (e.g.СИСТЕМАon Russian Windows). When Node.js reads the output, the multi-byte characters may be garbled, causing the auditor to misclassify SYSTEM as an unknown/untrusted principal and raise false-positive security alerts.Fix
Pass
/sidtoicaclsso it emits canonical ASCII SIDs (*S-1-5-18) instead of locale-specific names. Update:SID_REto accept the optional leading*that/sidprependsclassifyPrincipalto strip the*prefix before SID lookup, addWORLD_SIDSconstant so world-equivalent SIDs (S-1-1-0Everyone,S-1-5-11Authenticated Users,S-1-5-32-545BUILTIN\Users) are classified as"world"instead of falling through to"group"formatIcaclsResetCommandto use*S-1-5-18(SYSTEM SID) instead of the localized name in the reset commandTests added
*S-1-5-18(SID form of SYSTEM from /sid) → trusted*S-1-5-32-544(BUILTIN\Administrators SID from /sid) → trustedicaclscall assertion to verify/sidis passed*S-1-1-0(Everyone SID) → world (not group)*S-1-5-11(Authenticated Users SID) → world (not group)*S-1-5-32-545(BUILTIN\Users SID) → world (not group)CI: 29/29 checks pass ✅
Fixes #35834