{"record":{"id":"508bce21302d1b5f","repo":"golang/go","slug":"unexpected-shell-character-q-in-pkgconf-output","errorCode":null,"errorMessage":"unexpected shell character %q in pkgconf output","messagePattern":"unexpected shell character %q in pkgconf output","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/go/internal/work/exec.go","lineNumber":2013,"sourceCode":"\t\t\t// “preserve the literal value of each character”\n\t\t\tflag = append(flag, c)\n\t\t\tcontinue\n\t\tcase '\"':\n\t\t\t// “preserve the literal value of all characters within the double-quotes,\n\t\t\t// with the exception of …”\n\t\t\tswitch c {\n\t\t\tcase '`', '$', '\\\\':\n\t\t\tdefault:\n\t\t\t\tflag = append(flag, c)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\t// “The application shall quote the following characters if they are to\n\t\t// represent themselves:”\n\t\tswitch c {\n\t\tcase '|', '&', ';', '<', '>', '(', ')', '$', '`':\n\t\t\treturn nil, fmt.Errorf(\"unexpected shell character %q in pkgconf output\", c)\n\n\t\tcase '\\\\':\n\t\t\t// “A <backslash> that is not quoted shall preserve the literal value of\n\t\t\t// the following character, with the exception of a <newline>.”\n\t\t\tescaped = true\n\t\t\tcontinue\n\n\t\tcase '\"', '\\'':\n\t\t\tquote = c\n\t\t\tdidQuote = true\n\t\t\tcontinue\n\n\t\tcase ' ', '\\t', '\\n':\n\t\t\tif len(flag) > 0 || didQuote {\n\t\t\t\tflags = append(flags, string(flag))\n\t\t\t}\n\t\t\tflag, didQuote = flag[:0], false\n\t\t\tcontinue","sourceCodeStart":1995,"sourceCodeEnd":2031,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/cmd/go/internal/work/exec.go#L1995-L2031","documentation":"When parsing pkg-config (--cflags/--libs) output into compiler flags, the go command runs a shell-quoting parser that accepts a safe subset of characters. If a character matches none of the handled cases (| & ; < > ( ) $ ` \\ \" ' and whitespace handling) it falls through and is rejected. This is a security guard preventing pkg-config output from injecting shell commands or unsafe tokens into the compiler invocation.","triggerScenarios":"Fires in the pkg-config output parser at the default fall-through of the shell-character switch, when a character (e.g. *, ?, {, }, !, ~) appears that the parser does not recognize as safely quotable.","commonSituations":"A hand-edited or generated .pc file whose Cflags/Libs lines contain glob characters, tildes, or other shell metacharacters the parser refuses to pass through.","solutions":["Inspect the .pc file: run `pkg-config --cflags <pkg>` and look for unusual characters","Edit the .pc file to remove or properly quote the offending characters in Cflags/Libs","Point PKG_CONFIG_PATH at a directory with corrected .pc files"],"exampleFix":"# before (.pc file contains)\nCflags: -I/usr/include/foo*\n# after (remove glob characters)\nCflags: -I/usr/include/foo","handlingStrategy":"validation","validationCode":"// Pre-check pkg-config output for characters the go parser rejects\nout, err := exec.Command(\"pkg-config\", append([]string{\"--cflags\"}, pkgs...)...).Output()\nif err != nil { return err }\nfor _, b := range out {\n    switch b {\n    case '*', '?', '{', '}', '!', '~', '\\\\n', '\\\\r':\n        return fmt.Errorf(\"pkg-config output has unsafe char %q\", b)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Audit .pc files for glob/tilde/newline characters in Cflags and Libs","Prefer pkg-config modules shipped by the system over hand-written .pc files","Run `pkg-config --cflags --libs <pkg>` and eyeball the output before building with cgo"],"tags":["go-toolchain","cgo","pkg-config","security","shell-injection"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}