package bundle import ( "path/filepath" "strings" ) // allowlist.go holds the known-benign-pattern allowlist that controls the // false-positive blast radius of bundle scanning. Many legitimate skills ship a // native wheel, run curl|sh against their own release host, set soffice // LD_PRELOAD for document conversion, or point pip/npm at a corporate mirror. // These benign-but-scary idioms share surface features with attacks; the // allowlist downgrades matching findings so the scanner is not an FP cannon that // forces operators to globally suppress bundle_cross_file. // // SAFETY INVARIANT: the defanged exfil host (attacker.example, 198.51.100.0/24 // TEST-NET) is NEVER allowlisted, so a downgrade can never launder a real exfil // signal. // knownBenignHosts are package-registry/CDN hosts treated as legitimate mirror // targets. A registry rewrite to one of these is a corporate-mirror idiom, not // an attack. Matching is host-suffix aware (registry.corp.example matches an // entry "corp.example") via isKnownBenignHost. var knownBenignHosts = map[string]bool{ // Default public registries (rewriting "to" the default is a no-op, but the // string still appears in legit configs). "registry.npmjs.org": true, "pypi.org": true, "files.pythonhosted.org": true, "rubygems.org": true, "crates.io": true, "static.crates.io": true, "proxy.golang.org": true, "sum.golang.org": true, "repo.maven.apache.org": true, "repo1.maven.org": true, // Common trusted release/CDN hosts skills legitimately curl from. "github.com": true, "raw.githubusercontent.com": true, "objects.githubusercontent.com": true, "codeload.github.com": true, "registry.yarnpkg.com": true, "cdn.jsdelivr.net": true, "unpkg.com": true, } // benignHostSuffixes are corporate/enterprise mirror domains that legitimately // host private registries. A rewrite to a sub-host of one of these is a // known-benign corporate-mirror pattern. var benignHostSuffixes = []string{ "jfrog.io", "artifactory.com", "pkg.dev", // Google Artifact Registry "azure.com", // Azure Artifacts "visualstudio.com", "nexus.example", // documented corporate-mirror placeholder in the corpus "corp.example", // documented corporate-mirror placeholder in the corpus } // disallowedExfilHostFragments are NEVER allowlisted regardless of any other // rule (defense against an allowlist entry accidentally covering the corpus's // defanged exfil host). var disallowedExfilHostFragments = []string{ "attacker.example", "198.51.100.", } // isKnownBenignHost reports whether host (already lowercased, no scheme/path) is // a recognized legitimate registry/CDN/corporate-mirror. The defanged exfil host // is explicitly excluded. func isKnownBenignHost(host string) bool { host = strings.ToLower(strings.TrimSpace(host)) if host == "" { return false } // Strip a port if present. if i := strings.IndexByte(host, ':'); i >= 0 { host = host[:i] } for _, frag := range disallowedExfilHostFragments { if strings.Contains(host, frag) { return false } } if knownBenignHosts[host] { return true } for _, suf := range benignHostSuffixes { if host == suf || strings.HasSuffix(host, "."+suf) { return true } } return false } // internalHostSuffixes are multi-label corporate/private-network suffixes that // indicate an internal mirror rather than a public exfil host. A registry // rewrite pointing at one of these is the enterprise "configure the internal // cache" idiom (e.g. pypi.internal.example.com, registry.internal.example.com) // and must not corroborate on its own. var internalHostSuffixes = []string{ ".internal", // bare *.internal ".intra", // *.intra ".corp", // *.corp ".lan", // *.lan ".home.arpa", // RFC 8375 home-network reserved zone ".localdomain", // common single-host local suffix } // internalHostInfixes are multi-label internal markers that appear as an inner // label rather than a trailing suffix, e.g. "internal" in // pypi.internal.example.com / registry.internal.example.com (the corpus's // corporate-mirror placeholder). Matched as a dot-delimited label so a host like // "internalattacker.example" does NOT match. var internalHostInfixes = []string{ ".internal.", ".intra.", ".corp.", } // isInternalRegistryHost reports whether host (lowercased, no scheme/path) is an // internal/private registry mirror destination: an RFC1918 / loopback IP, a // localhost name, or a host under an internal/corp suffix or infix. A rewrite to // such a host is a benign enterprise mirror idiom and must NOT corroborate. // // SAFETY: the defanged exfil host (attacker.example, 198.51.100.0/24 TEST-NET) // is checked FIRST and can never be classified as internal, so a real exfil // signal can never be laundered through this downgrade. func isInternalRegistryHost(host string) bool { host = strings.ToLower(strings.TrimSpace(host)) if host == "" { return false } // Unwrap a bracketed IPv6 literal, optionally followed by ":port". if strings.HasPrefix(host, "[") { if end := strings.IndexByte(host, ']'); end >= 0 { host = host[1:end] } else { host = strings.TrimLeft(host, "[") } } else if strings.Count(host, ":") == 1 { // A single colon is a host:port separator (bare IPv6 has >=2 colons). host = host[:strings.IndexByte(host, ':')] } if host == "" { return false } // SAFETY GUARD FIRST: never downgrade the defanged exfil host. for _, frag := range disallowedExfilHostFragments { if strings.Contains(host, frag) { return false } } // Loopback / localhost names and literals. if host == "localhost" || host == "127.0.0.1" || host == "::1" || strings.HasSuffix(host, ".localhost") { return true } // RFC1918 private IPv4 ranges. if isPrivateIPv4(host) { return true } // Internal/corp multi-label suffixes (trailing). for _, suf := range internalHostSuffixes { if strings.HasSuffix(host, suf) { return true } } // Internal/corp markers as an inner label (e.g. *.internal.example.com). for _, inf := range internalHostInfixes { if strings.Contains(host, inf) { return true } } return false } // isPrivateIPv4 reports whether host is a dotted-quad in an RFC1918 private // range: 10.0.0.0/8, 172.16.0.0/12, or 192.168.0.0/16. Non-IP hosts return // false. func isPrivateIPv4(host string) bool { parts := strings.Split(host, ".") if len(parts) != 4 { return false } octets := make([]int, 4) for i, p := range parts { if p == "" || len(p) > 3 { return false } n := 0 for _, c := range p { if c < '0' || c > '9' { return false } n = n*10 + int(c-'0') } if n > 255 { return false } octets[i] = n } switch { case octets[0] == 10: return true case octets[0] == 172 && octets[1] >= 16 && octets[1] <= 31: return true case octets[0] == 192 && octets[1] == 168: return true } return false } // isKnownBenignNativePattern reports whether a native binary file matches a // common legitimate shipping pattern (a signed/platform-tagged native wheel or // a Node native addon) so a bare .so does not self-escalate. This is a // precision lever only: a binary that embeds the exfil host or dangerous // symbols is handled by the analyzer BEFORE this downgrade is consulted. func isKnownBenignNativePattern(f *File) bool { if f == nil { return false } base := strings.ToLower(filepath.Base(f.RelPath)) // Node native addon convention. if strings.HasSuffix(base, ".node") { return true } // Python extension modules carry an ABI tag, e.g. // "_speedups.cpython-312-x86_64-linux-gnu.so" or "...-darwin.so". if strings.HasSuffix(base, ".so") || strings.HasSuffix(base, ".dylib") { if strings.Contains(base, ".cpython-") || strings.Contains(base, ".abi3.") || strings.Contains(base, "-x86_64-") || strings.Contains(base, "-aarch64-") || strings.Contains(base, "-arm64-") || strings.Contains(base, "-darwin") || strings.Contains(base, "-linux-gnu") { return true } } return false } // isKnownBenignScriptIdiom reports whether a script line matches a benign-but- // scary idiom that should not, on its own, escalate. Examples: setting // LD_PRELOAD for soffice/libreoffice document conversion, or rustup/nvm-style // installers fetching from their own canonical host. Lines containing the // defanged exfil host are never benign. func isKnownBenignScriptIdiom(line string) bool { low := strings.ToLower(line) for _, frag := range disallowedExfilHostFragments { if strings.Contains(low, frag) { return false } } // soffice/libreoffice LD_PRELOAD doc-conversion idiom. if strings.Contains(low, "ld_preload") && (strings.Contains(low, "soffice") || strings.Contains(low, "libreoffice") || strings.Contains(low, "unoconv")) { return true } // Canonical first-party installers fetched from their own hosts. benignInstallerHosts := []string{ "sh.rustup.rs", "static.rust-lang.org", "raw.githubusercontent.com/nvm-sh", "get.docker.com", "deb.nodesource.com", "rpm.nodesource.com", "install.python-poetry.org", } if matchedAny(low, benignInstallerHosts) { return true } return false }