-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ Open Source Semgrep codemods (#448)
- **:truck: open source semgrep codemods** - **:sparkles: add semgrep codemods**
- Loading branch information
Showing
59 changed files
with
299,685 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
114 changes: 114 additions & 0 deletions
114
...codemods/src/main/java/io/codemodder/codemods/remediators/ssrf/DefaultSSRFRemediator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package io.codemodder.codemods.remediators.ssrf; | ||
|
||
import static io.codemodder.ast.ASTTransforms.addImportIfMissing; | ||
|
||
import com.github.javaparser.ast.CompilationUnit; | ||
import com.github.javaparser.ast.NodeList; | ||
import com.github.javaparser.ast.expr.Expression; | ||
import com.github.javaparser.ast.expr.FieldAccessExpr; | ||
import com.github.javaparser.ast.expr.MethodCallExpr; | ||
import com.github.javaparser.ast.expr.NameExpr; | ||
import com.github.javaparser.ast.expr.ObjectCreationExpr; | ||
import io.codemodder.CodemodChange; | ||
import io.codemodder.CodemodFileScanningResult; | ||
import io.codemodder.DependencyGAV; | ||
import io.codemodder.codetf.DetectorRule; | ||
import io.codemodder.codetf.FixedFinding; | ||
import io.codemodder.codetf.UnfixedFinding; | ||
import io.codemodder.remediation.FixCandidate; | ||
import io.codemodder.remediation.FixCandidateSearchResults; | ||
import io.codemodder.remediation.FixCandidateSearcher; | ||
import io.github.pixee.security.HostValidator; | ||
import io.github.pixee.security.Urls; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.function.Function; | ||
|
||
final class DefaultSSRFRemediator implements SSRFRemediator { | ||
|
||
@Override | ||
public <T> CodemodFileScanningResult remediateAll( | ||
final CompilationUnit cu, | ||
final String path, | ||
final DetectorRule detectorRule, | ||
final List<T> issuesForFile, | ||
final Function<T, String> getKey, | ||
final Function<T, Integer> getStartLine, | ||
final Function<T, Integer> getEndLine, | ||
final Function<T, Integer> getStartColumn) { | ||
|
||
// search for new URL() calls on those lines, assuming the tool points there -- there are plenty | ||
// of more signatures to chase down | ||
FixCandidateSearcher<T> searcher = | ||
new FixCandidateSearcher.Builder<T>() | ||
.withMatcher(mce -> mce.isConstructorForType("URL")) | ||
.withMatcher(mce -> !mce.getArguments().isEmpty()) | ||
.build(); | ||
|
||
FixCandidateSearchResults<T> results = | ||
searcher.search( | ||
cu, | ||
path, | ||
detectorRule, | ||
issuesForFile, | ||
getKey, | ||
getStartLine, | ||
getEndLine, | ||
getStartColumn); | ||
|
||
List<CodemodChange> changes = new ArrayList<>(); | ||
|
||
for (FixCandidate<T> candidate : results.fixCandidates()) { | ||
ObjectCreationExpr call = (ObjectCreationExpr) candidate.call().asNode(); | ||
List<T> issues = candidate.issues(); | ||
harden(cu, call); | ||
List<FixedFinding> fixedFindings = | ||
issues.stream() | ||
.map(issue -> new FixedFinding(getKey.apply(issue), detectorRule)) | ||
.toList(); | ||
CodemodChange change = | ||
CodemodChange.from( | ||
getStartLine.apply(issues.get(0)), | ||
List.of(DependencyGAV.JAVA_SECURITY_TOOLKIT), | ||
fixedFindings); | ||
changes.add(change); | ||
} | ||
|
||
List<UnfixedFinding> unfixedFindings = new ArrayList<>(results.unfixableFindings()); | ||
return CodemodFileScanningResult.from(changes, unfixedFindings); | ||
} | ||
|
||
private void harden(final CompilationUnit cu, final ObjectCreationExpr newUrlCall) { | ||
NodeList<Expression> arguments = newUrlCall.getArguments(); | ||
|
||
/* | ||
* We need to replace: | ||
* | ||
* URL u = new URL(foo) | ||
* | ||
* With: | ||
* | ||
* import io.github.pixee.security.Urls; | ||
* ... | ||
* URL u = Urls.create(foo, io.github.pixee.security.Urls.HTTP_PROTOCOLS, io.github.pixee.security.HostValidator.ALLOW_ALL) | ||
*/ | ||
addImportIfMissing(cu, Urls.class.getName()); | ||
addImportIfMissing(cu, HostValidator.class.getName()); | ||
FieldAccessExpr httpProtocolsExpr = new FieldAccessExpr(); | ||
httpProtocolsExpr.setScope(new NameExpr(Urls.class.getSimpleName())); | ||
httpProtocolsExpr.setName("HTTP_PROTOCOLS"); | ||
|
||
FieldAccessExpr denyCommonTargetsExpr = new FieldAccessExpr(); | ||
|
||
denyCommonTargetsExpr.setScope(new NameExpr(HostValidator.class.getSimpleName())); | ||
denyCommonTargetsExpr.setName("DENY_COMMON_INFRASTRUCTURE_TARGETS"); | ||
|
||
NodeList<Expression> newArguments = new NodeList<>(); | ||
newArguments.addAll(arguments); // first are all the arguments they were passing to "new URL" | ||
newArguments.add(httpProtocolsExpr); // load the protocols they're allowed | ||
newArguments.add(denyCommonTargetsExpr); // load the host validator | ||
MethodCallExpr safeCall = | ||
new MethodCallExpr(new NameExpr(Urls.class.getSimpleName()), "create", newArguments); | ||
newUrlCall.replace(safeCall); | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
core-codemods/src/main/java/io/codemodder/codemods/remediators/ssrf/SSRFRemediator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package io.codemodder.codemods.remediators.ssrf; | ||
|
||
import com.github.javaparser.ast.CompilationUnit; | ||
import io.codemodder.CodemodFileScanningResult; | ||
import io.codemodder.codetf.DetectorRule; | ||
import java.util.List; | ||
import java.util.function.Function; | ||
|
||
/** Fixes SSRF vulnerabilities. */ | ||
public interface SSRFRemediator { | ||
|
||
/** A default implementation for callers. */ | ||
SSRFRemediator DEFAULT = new DefaultSSRFRemediator(); | ||
|
||
/** Remediate all SSRF vulnerabilities in the given compilation unit. */ | ||
<T> CodemodFileScanningResult remediateAll( | ||
CompilationUnit cu, | ||
String path, | ||
DetectorRule detectorRule, | ||
List<T> issuesForFile, | ||
Function<T, String> getKey, | ||
Function<T, Integer> getStartLine, | ||
Function<T, Integer> getEndLine, | ||
Function<T, Integer> getColumn); | ||
} |
78 changes: 78 additions & 0 deletions
78
.../main/java/io/codemodder/codemods/remediators/weakrandom/DefaultWeakRandomRemediator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package io.codemodder.codemods.remediators.weakrandom; | ||
|
||
import static io.codemodder.ast.ASTTransforms.addImportIfMissing; | ||
|
||
import com.github.javaparser.ast.CompilationUnit; | ||
import com.github.javaparser.ast.expr.ObjectCreationExpr; | ||
import io.codemodder.CodemodChange; | ||
import io.codemodder.CodemodFileScanningResult; | ||
import io.codemodder.codetf.DetectorRule; | ||
import io.codemodder.codetf.FixedFinding; | ||
import io.codemodder.codetf.UnfixedFinding; | ||
import io.codemodder.remediation.RemediationMessages; | ||
import java.security.SecureRandom; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.function.Function; | ||
|
||
final class DefaultWeakRandomRemediator implements WeakRandomRemediator { | ||
|
||
@Override | ||
public <T> CodemodFileScanningResult remediateAll( | ||
final CompilationUnit cu, | ||
final String path, | ||
final DetectorRule detectorRule, | ||
final List<T> issuesForFile, | ||
final Function<T, String> getKey, | ||
final Function<T, Integer> getLine, | ||
final Function<T, Integer> getColumn) { | ||
|
||
List<UnfixedFinding> unfixedFindings = new ArrayList<>(); | ||
List<CodemodChange> changes = new ArrayList<>(); | ||
|
||
for (T issue : issuesForFile) { | ||
|
||
List<ObjectCreationExpr> unsafeRandoms = | ||
cu.findAll(ObjectCreationExpr.class).stream() | ||
.filter(oc -> oc.getType().asString().equals("Random")) | ||
.filter(oc -> getLine.apply(issue) == oc.getRange().get().begin.line) | ||
.filter( | ||
oc -> { | ||
Integer column = getColumn.apply(issue); | ||
return column == null || column == oc.getRange().get().begin.column; | ||
}) | ||
.toList(); | ||
|
||
if (unsafeRandoms.size() > 1) { | ||
unfixedFindings.add( | ||
new UnfixedFinding( | ||
getKey.apply(issue), | ||
detectorRule, | ||
path, | ||
getLine.apply(issue), | ||
RemediationMessages.multipleCallsFound)); | ||
continue; | ||
} else if (unsafeRandoms.isEmpty()) { | ||
unfixedFindings.add( | ||
new UnfixedFinding( | ||
getKey.apply(issue), | ||
detectorRule, | ||
path, | ||
getLine.apply(issue), | ||
RemediationMessages.noCallsAtThatLocation)); | ||
continue; | ||
} | ||
|
||
ObjectCreationExpr unsafeRandom = unsafeRandoms.get(0); | ||
unsafeRandom.setType("SecureRandom"); | ||
addImportIfMissing(cu, SecureRandom.class.getName()); | ||
changes.add( | ||
CodemodChange.from( | ||
getLine.apply(issue), | ||
List.of(), | ||
List.of(new FixedFinding(getKey.apply(issue), detectorRule)))); | ||
} | ||
|
||
return CodemodFileScanningResult.from(changes, unfixedFindings); | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
...ods/src/main/java/io/codemodder/codemods/remediators/weakrandom/WeakRandomRemediator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package io.codemodder.codemods.remediators.weakrandom; | ||
|
||
import com.github.javaparser.ast.CompilationUnit; | ||
import io.codemodder.CodemodFileScanningResult; | ||
import io.codemodder.codetf.DetectorRule; | ||
import java.util.List; | ||
import java.util.function.Function; | ||
|
||
/** Fixes weak randomness. */ | ||
public interface WeakRandomRemediator { | ||
|
||
/** A default implementation for callers. */ | ||
WeakRandomRemediator DEFAULT = new DefaultWeakRandomRemediator(); | ||
|
||
/** Remediate all weak random vulnerabilities in the given compilation unit. */ | ||
<T> CodemodFileScanningResult remediateAll( | ||
CompilationUnit cu, | ||
String path, | ||
DetectorRule detectorRule, | ||
List<T> issuesForFile, | ||
Function<T, String> getKey, | ||
Function<T, Integer> getLine, | ||
Function<T, Integer> getColumn); | ||
} |
61 changes: 61 additions & 0 deletions
61
...emods/src/main/java/io/codemodder/codemods/semgrep/SemgrepJavaDeserializationCodemod.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package io.codemodder.codemods.semgrep; | ||
|
||
import com.github.javaparser.ast.CompilationUnit; | ||
import io.codemodder.Codemod; | ||
import io.codemodder.CodemodExecutionPriority; | ||
import io.codemodder.CodemodFileScanningResult; | ||
import io.codemodder.CodemodInvocationContext; | ||
import io.codemodder.Importance; | ||
import io.codemodder.ReviewGuidance; | ||
import io.codemodder.RuleSarif; | ||
import io.codemodder.SarifFindingKeyUtil; | ||
import io.codemodder.codetf.DetectorRule; | ||
import io.codemodder.providers.sarif.semgrep.ProvidedSemgrepScan; | ||
import io.codemodder.remediation.GenericRemediationMetadata; | ||
import io.codemodder.remediation.javadeserialization.JavaDeserializationRemediator; | ||
import javax.inject.Inject; | ||
|
||
/** | ||
* Fixes some Semgrep issues reported under the id | ||
* "java.lang.security.audit.object-deserialization.object-deserialization". | ||
*/ | ||
@Codemod( | ||
id = "semgrep:java/java.lang.security.audit.object-deserialization.object-deserialization", | ||
reviewGuidance = ReviewGuidance.MERGE_WITHOUT_REVIEW, | ||
executionPriority = CodemodExecutionPriority.HIGH, | ||
importance = Importance.HIGH) | ||
public final class SemgrepJavaDeserializationCodemod extends SemgrepJavaParserChanger { | ||
|
||
private final JavaDeserializationRemediator remediator; | ||
|
||
@Inject | ||
public SemgrepJavaDeserializationCodemod( | ||
@ProvidedSemgrepScan( | ||
ruleId = "java.lang.security.audit.object-deserialization.object-deserialization") | ||
final RuleSarif sarif) { | ||
super(GenericRemediationMetadata.DESERIALIZATION.reporter(), sarif); | ||
this.remediator = JavaDeserializationRemediator.DEFAULT; | ||
} | ||
|
||
@Override | ||
public DetectorRule detectorRule() { | ||
return new DetectorRule( | ||
ruleSarif.getRule(), | ||
"Insecure Deserialization", | ||
"https://semgrep.dev/playground/r/java.lang.security.audit.object-deserialization.object-deserialization"); | ||
} | ||
|
||
@Override | ||
public CodemodFileScanningResult visit( | ||
final CodemodInvocationContext context, final CompilationUnit cu) { | ||
return remediator.remediateAll( | ||
cu, | ||
context.path().toString(), | ||
detectorRule(), | ||
ruleSarif.getResultsByLocationPath(context.path()), | ||
SarifFindingKeyUtil::buildFindingId, | ||
r -> r.getLocations().get(0).getPhysicalLocation().getRegion().getStartLine(), | ||
r -> r.getLocations().get(0).getPhysicalLocation().getRegion().getEndLine(), | ||
r -> r.getLocations().get(0).getPhysicalLocation().getRegion().getStartColumn()); | ||
} | ||
} |
Oops, something went wrong.