Skip to content

Unified: Add command injection query. - #22879

Draft
geoffw0 wants to merge 7 commits into
github:mainfrom
geoffw0:unifiedcommandinjection
Draft

geoffw0 wants to merge 7 commits into
github:mainfrom
geoffw0:unifiedcommandinjection

Conversation

@geoffw0

@geoffw0 geoffw0 commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Adds a unified/swift/command-line-injection query for unified Swift. I got Copilot to do this step-by-step, first copying files from the original Swift implementation, then updating the structure, porting the QL itself, and finally fixing a couple of issues. The original tests are preserved and test annotations updated so we can see where we stand. Tiny bit of manual fixup afterwards.

I'll share a skill to do all this when it's sufficiently mature / proven.

The query only finds a couple of the test cases right now. I'm pretty sure we're missing some relevant summary models, and there might be other issues e.g. with data flow. But it's time to share what I have and open it up to discussion.

TODO: review DCA run.

geoffw0 and others added 7 commits October 23, 2026 17:59
Copy the original Swift query, help, examples, and regression test files unchanged as a reviewable baseline for the unified port. Metadata, imports, and test references will be adapted in subsequent commits.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Inline CommandInjectionQuery.qll and CommandInjectionExtensions.qll in the query, preserving their declarations and required shared imports. Keep this source-collection step separate from the unified API port; the query is not expected to compile yet.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use unified taint tracking and the existing command-injection models, update the query ID and test reference, and enable inline expectation checks. Leave TODOs for Process property sinks and the original numeric barrier.

Learn the focused regression test and annotate missing behavior explicitly. The query currently reports two alerts with no inline expectation failures; further modeling and flow improvements are left for follow-up commits.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add the model-as-data selector for calls that omit terminationHandler, retaining the existing full-argument model. This detects the previously missing executable-URL case without query-local model code.

Cover explicit and omitted termination handlers with positive and safe cases. The command-injection test now reports four alerts with no expectation failures; both it and the path-injection test pass without --learn.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the OWASP link returning 404 with its current canonical page (verified HTTP 200). Explain fixed executables, separate arguments, and allowlisting complete shell commands so the guidance matches the examples.

Clarify which test comments describe original Swift false positives or currently missing alerts. Help XML and example paths validate, and the focused test passes with unchanged results.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ll they don't really fix anything just rephrase?).
@geoffw0 geoffw0 added no-change-note-required This PR does not need a change note Unified labels Oct 23, 2026
@github-actions

Copy link
Copy Markdown
Contributor

QHelp previews:

unified/ql/src/queries/security/CWE-078/CommandInjection.qhelp

System command built from user-controlled sources

Constructing a system command with unsanitized user input is dangerous, since a malicious user may be able to craft input that executes arbitrary code.

Recommendation

If possible, use hard-coded string literals to specify the command to run. Instead of interpreting user input directly as command names, examine the input and then choose among hard-coded string literals.

If this is not possible, then add sanitization code to verify that the user input is safe before using it.

Example

The following example executes code from user input without sanitizing it first:

var task = Process()
task.launchPath = "/bin/bash"
task.arguments = ["-c", userControlledString] // BAD

task.launch()

If user input is used to construct a command it should be checked first. This ensures that the user cannot insert characters that have special meanings:

func validateCommand(_ command: String) -> String? {
    let allowedCommands = ["ls -l", "pwd", "echo"]
    if allowedCommands.contains(command) {
        return command
    }
    return nil
}

if let validatedString = validateCommand(userControlledString) {
    var task = Process()
    task.launchPath = "/bin/bash"
    task.arguments = ["-c", validatedString] // GOOD

    task.launch()
}

References

- ["", "Process", true, "launchPath", "", "", "PostUpdate", "command-injection", "manual"]
- ["", "Process", true, "launchedProcess(arguments:launchPath:)", "", "", "Argument[launchPath:,arguments:]", "command-injection", "manual"]
# Calls may omit the defaulted terminationHandler argument.
- ["", "Process", true, "run(_:arguments:)", "", "", "Argument[0,arguments:]", "command-injection", "manual"]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@asgerf Copilot added this near-duplicate of the model below, and it does indeed let us catch an additional test case where the default argument value for terminationHandler is used. But I suspect we might prefer a general fix for default arguments in the logic that matches models with function calls?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes, I'm aware of the limitation and expect to make a general fix for this. But it's not a small fix.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation no-change-note-required This PR does not need a change note Unified

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants