Skip to content

Commit

Permalink
semgrep url sandbox codemod (#754)
Browse files Browse the repository at this point in the history
new semgrep url sandbox codemod
  • Loading branch information
clavedeluna authored Jul 29, 2024
1 parent 1231122 commit d6c64ed
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/codemodder/scripts/generate_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ class DocMetadata:
}

SEMGREP_CODEMOD_NAMES = [
"url-sandbox",
"enable-jinja2-autoescape",
"jwt-decode-verify",
"use-defusedxml",
Expand Down
2 changes: 2 additions & 0 deletions src/core_codemods/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
from .semgrep.semgrep_rsa_key_size import SemgrepRsaKeySize
from .semgrep.semgrep_sql_parametrization import SemgrepSQLParameterization
from .semgrep.semgrep_subprocess_shell_false import SemgrepSubprocessShellFalse
from .semgrep.semgrep_url_sandbox import SemgrepUrlSandbox
from .semgrep.semgrep_use_defused_xml import SemgrepUseDefusedXml
from .sonar.sonar_break_or_continue_out_of_loop import SonarBreakOrContinueOutOfLoop
from .sonar.sonar_disable_graphql_introspection import SonarDisableGraphQLIntrospection
Expand Down Expand Up @@ -204,6 +205,7 @@
semgrep_registry = CodemodCollection(
origin="semgrep",
codemods=[
SemgrepUrlSandbox,
SemgrepEnableJinja2Autoescape,
SemgrepJwtDecodeVerify,
SemgrepUseDefusedXml,
Expand Down
23 changes: 23 additions & 0 deletions src/core_codemods/semgrep/semgrep_url_sandbox.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from core_codemods.semgrep.api import SemgrepCodemod, ToolRule, semgrep_url_from_id
from core_codemods.url_sandbox import UrlSandbox

SemgrepUrlSandbox = SemgrepCodemod.from_core_codemod(
name="url-sandbox",
other=UrlSandbox,
rules=[
ToolRule(
id=(
rule_id := "python.django.security.injection.ssrf.ssrf-injection-requests.ssrf-injection-requests"
),
name="ssrf-injection-requests",
url=semgrep_url_from_id(rule_id),
),
ToolRule(
id=(
rule_id := "python.flask.security.injection.ssrf-requests.ssrf-requests"
),
name="ssrf-requests",
url=semgrep_url_from_id(rule_id),
),
],
)
109 changes: 109 additions & 0 deletions tests/codemods/semgrep/test_semgrep_url_sandbox.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import json

from codemodder.codemods.test import BaseSASTCodemodTest
from core_codemods.semgrep.semgrep_url_sandbox import SemgrepUrlSandbox


class TestSemgrepUrlSandbox(BaseSASTCodemodTest):
codemod = SemgrepUrlSandbox
tool = "semgrep"

def test_name(self):
assert self.codemod.name == "url-sandbox"

def test_url_sandbox(self, tmpdir):
original_code = """\
import requests
from flask import Flask, request
app = Flask(__name__)
@app.route("/example")
def example():
url = request.args["url"]
requests.get(url)
"""

new_code = """\
from flask import Flask, request
from security import safe_requests
app = Flask(__name__)
@app.route("/example")
def example():
url = request.args["url"]
safe_requests.get(url)
"""

results = {
"runs": [
{
"results": [
{
"fingerprints": {"matchBasedId/v1": "370059975f"},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "code.py",
"uriBaseId": "%SRCROOT%",
},
"region": {
"endColumn": 22,
"endLine": 10,
"snippet": {
"text": ' url = request.args["url"]\n requests.get(url)'
},
"startColumn": 5,
"startLine": 9,
},
}
}
],
"message": {
"text": "Data from request object is passed to a new server-side request. This could lead to a server-side request forgery (SSRF). To mitigate, ensure that schemes and hosts are validated against an allowlist, do not forward the response to the user, and ensure proper authentication and transport-layer security in the proxied request. See https://owasp.org/www-community/attacks/Server_Side_Request_Forgery to learn more about SSRF vulnerabilities."
},
"properties": {},
"ruleId": "python.django.security.injection.ssrf.ssrf-injection-requests.ssrf-injection-requests",
},
{
"fingerprints": {"matchBasedId/v1": "cd899"},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "code.py",
"uriBaseId": "%SRCROOT%",
},
"region": {
"endColumn": 22,
"endLine": 10,
"snippet": {
"text": " requests.get(url)"
},
"startColumn": 5,
"startLine": 10,
},
}
}
],
"message": {
"text": "Data from request object is passed to a new server-side request. This could lead to a server-side request forgery (SSRF). To mitigate, ensure that schemes and hosts are validated against an allowlist, do not forward the response to the user, and ensure proper authentication and transport-layer security in the proxied request."
},
"properties": {},
"ruleId": "python.flask.security.injection.ssrf-requests.ssrf-requests",
},
],
}
]
}

self.run_and_assert(
tmpdir,
original_code,
new_code,
results=json.dumps(results),
)

0 comments on commit d6c64ed

Please sign in to comment.