Skip to content

csharp: odata lib - #22384

Open
hugo-syn wants to merge 3 commits into
github:mainfrom
hugo-syn:hugo-syn/csharp-odata-tainted-member
Open

csharp: odata lib #22384
hugo-syn wants to merge 3 commits into
github:mainfrom
hugo-syn:hugo-syn/csharp-odata-tainted-member

Conversation

@hugo-syn

Copy link
Copy Markdown

hugo-syn and others added 3 commits August 19, 2026 15:30
Adds semmle.code.csharp.frameworks.OData, following the WCF.qll/JsonNET.qll
convention: values cast, as-converted, or type-tested out of an untyped
ODataActionParameters dictionary, and entities tracked by Delta<T> (via
GetInstance/Patch/Put/CopyChangedValues/CopyUnchangedValues), have no static
type relationship to the action method's own parameter types, so their
members aren't picked up by the existing AspNetRemoteFlowSourceMember
modeling. This adds a TaintedMember for those bound types (with the same
nested-type/collection recursion as AspNetRemoteFlowSourceMember), plus two
AdditionalTaintStep steps for the Delta<T> method calls, which don't fit the
member-read shape TaintedMember covers.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Match WCF.qll's convention: only the TaintedMember/AdditionalTaintStep
wiring classes stay private, everything else that identifies a reusable
OData domain concept (ODataActionParametersClass, DeltaClass,
ODataBoundType, DeltaMutatingMethod, DeltaGetInstanceMethod) is public.

Also renames the test fixtures to generic placeholder names.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
import csharp already publicly imports semmle.code.csharp.dataflow.TaintTracking
(and DataFlow), same as WCF.qll/JsonNET.qll rely on implicitly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@hugo-syn
hugo-syn requested a review from a team as a code owner August 19, 2026 13:57

@michaelnebel michaelnebel left a comment

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.

Thank you very much! It is really good, if we can get our modelling extended even further!

I have added some initial comments / questions. Maybe OData parameter like types are only relevant for classes that extend ODataController. Should that somehow be incorporated in the logic?

Comment on lines +152 to +160
private class DeltaGetInstanceTaintStep extends AdditionalTaintStep {
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
exists(MethodCall mc |
mc.getTarget().getUnboundDeclaration() instanceof DeltaGetInstanceMethod and
node1.asExpr() = mc.getQualifier() and
node2.asExpr() = mc
)
}
}

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.

Perhaps, the QL implementation can be replaced by Models as Data?
Below is the row for one of the GetInstance methods.

extensions:
  - addsTo:
      pack: codeql/csharp-all
      extensible: summaryModel
    data:
      - ["Microsoft.AspNet.OData", "Delta<TStructuralType>", True, "GetInstance", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"]

Comment on lines +3 to +25
namespace Microsoft.AspNet.OData
{
public class ODataActionParameters : Dictionary<string, object>
{
}

public class Delta<TStructuralType> where TStructuralType : class
{
private TStructuralType instance;

public Delta() { instance = default(TStructuralType); }

public TStructuralType GetInstance() => instance;

public void Patch(TStructuralType original) { }

public void Put(TStructuralType original) { }

public void CopyChangedValues(TStructuralType original) { }

public void CopyUnchangedValues(TStructuralType original) { }
}
}

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.

Ideally, we would like to keep stub implementations separate from the test and store them in test/resources/stubs.
This will require an options file for the test; If possible, it is also preferred, if the test relies fully on stubs and not any .dll files.

Comment on lines +97 to +112
private class CandidateODataMember extends Member {
CandidateODataMember() {
this.isPublic() and
not this.isStatic() and
(
this =
any(Property p |
p.isAutoImplemented() and
p.getGetter().isPublic() and
p.getSetter().isPublic()
)
or
this = any(Field f | f.isPublic())
)
}
}

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.

This appears to be a copy of the CandidateMemberToTaint. Perhaps, the implementation from Remote.qll can be re-used?

TaintTracking::localExprTaint(any(ODataActionParameterRead r), e)
}

/** The generic `Delta<TStructuralType>` change-tracking class, across OData library versions. */

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.

Maybe refer to the unbound declaration with "Delta1" instead of Delta<TStructuralType> as the type parameter is named T for Microsoft.AspNetCore.OData.Deltas.Delta<T>

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants