Skip to content

Conversation

chanel-y
Copy link

@chanel-y chanel-y commented Sep 4, 2025

Couple of changes in this one suggested by @ewilloner

  • Adding Start-Process as a sink
  • Adding ValidatePattern and ValidateSet as sanitizers
  • CommandInjectionCritical variant, only considering params to functions with CmdletBinding as source
  • Removing Invoke-WebRequest as a source. Campaign had some examples like this: https://codeql.microsoft.com/issues/151432cf-6484-4839-9784-f45700c1995c?Campaign=powershell_commandinjection, where a file or executable from a hardcoded url was considered unsafe input. Future ssrf-y queries should trace user input to Invoke-WebRequest and Invoke-RestMethod, but not for this query

Copy link
Collaborator

@MathiasVP MathiasVP left a comment

Choose a reason for hiding this comment

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

LGTM! One comment, but that's not blocking!

class CmdletBindingParam extends CriticalSource {
CmdletBindingParam(){
exists(Attribute a, Function f |
a.getName() = "CmdletBinding" and
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should probably to case insensitive matching since I'm sure PowerShell happily accepts cMdlEtBinDinG. But I'll fix that in another since we don't have an API for this on Attribute yet.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I've fixed this here.

exists(Function f, Attribute a, Parameter p |
p = f.getAParameter() and
p.getAnAttribute() = a and
a.getName() = ["ValidateScript", "ValidateSet", "ValidatePattern"] and
Copy link
Collaborator

Choose a reason for hiding this comment

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

Again: I'll do another PR to make this case insensitive. Thanks for adding this!

Copy link
Collaborator

Choose a reason for hiding this comment

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

Fixed here.

@@ -34,12 +34,19 @@ module CommandInjection {
class FlowSourceAsSource extends Source {
FlowSourceAsSource() {
this instanceof SourceNode and
not this instanceof EnvironmentVariableSource
not this instanceof EnvironmentVariableSource and
not this instanceof InvokeWebRequest
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we only remove it when it's given a constant string literal as a source? Or do you think it's better to totally remove it like you're doing here?

Copy link
Author

Choose a reason for hiding this comment

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

I think totally remove it. It could be a case if there's flow from user input -> InvokeWebRequest -> command call, but that's more of an SSRF vuln first, which we can model as a separate query

@MathiasVP MathiasVP merged commit c8b2fda into main Sep 5, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants