fix(exec): stop privilege-escalation su deny matching non-ASCII text (#1389)

Go's regexp (RE2) treats \b as an ASCII-only word boundary, so the
privilege_escalation deny pattern \bsu\b matched the ASCII "su" inside
non-ASCII words such as the Vietnamese "suất" — the accented 'ấ' is not
an ASCII word char, so \b sees a spurious word boundary right after "su".

Any exec command containing such a word (for example a Vietnamese
document embedded in a python heredoc to render a PDF) was wrongly
blocked as a privilege-escalation attempt. Replace the pattern with a
Unicode-aware boundary (\pL, \pN) that still matches the real su command.
This commit is contained in:
Duc Nguyen authored and GitHub committed 2026-07-08 07:23:05 +07:00
1 parent e65f70e2ef
commit 8367a9bd0c
2 files changed
+25 -9

No files matched your search

+12 -1
View File
@@ -4,6 +4,17 @@ import (
"regexp"
)
// unicodeCmdWord matches a command name (or alternation) as a standalone
// word using a Unicode-aware boundary. Go's RE2 \b is ASCII-only, so a
// pattern like \bsu\b matches the "su" inside non-ASCII words such as the
// Vietnamese "suất" (the accented 'ấ' is not an ASCII word char, so \b
// sees a spurious boundary right after "su"). Treating Unicode letters and
// digits (\pL, \pN) as word chars avoids those false positives while still
// matching the real `su` command.
func unicodeCmdWord(alt string) *regexp.Regexp {
return regexp.MustCompile(`(?:^|[^\pL\pN_])(?:` + alt + `)(?:[^\pL\pN_]|$)`)
}
// DenyGroup is a named set of shell command deny patterns.
type DenyGroup struct {
Name string // machine name: "package_install"
@@ -83,7 +94,7 @@ var DenyGroupRegistry = map[string]*DenyGroup{
Default: true,
Patterns: []*regexp.Regexp{
regexp.MustCompile(`\bsudo\b`),
regexp.MustCompile(`\bsu\b`),
unicodeCmdWord("su"),
regexp.MustCompile(`\bdoas\b`),
regexp.MustCompile(`\bpkexec\b`),
regexp.MustCompile(`\brunuser\b`),
+13 -8
View File
@@ -130,14 +130,19 @@ func TestPrivilegeEscalationGaps(t *testing.T) {
)
mustAllow(t, patterns,
"summit", // not "su"
"sugar", // not "su"
"surplus", // not "su"
"issue", // not "su"
"result", // not "su"
"resume", // not "su"
"visual", // not "su"
"sushi", // not "su"
"summit", // not "su"
"sugar", // not "su"
"surplus", // not "su"
"issue", // not "su"
"result", // not "su"
"resume", // not "su"
"visual", // not "su"
"sushi", // not "su"
// non-ASCII (Vietnamese) text: ASCII "su" adjacent to an accented
// vowel must NOT match the su command (Go RE2 word boundaries are ASCII-only).
"hiệu suất",
"năng suất",
"báo cáo hiệu suất tháng",
"doaspkg", // not "doas" (no word boundary)
"pkexecute", // not "pkexec" (no word boundary)
)