77from libcst .metadata import PositionProvider , ScopeProvider
88
99from codemodder .codemods .base_visitor import UtilsMixin
10+ from codemodder .codemods .libcst_transformer import (
11+ LibcstResultTransformer ,
12+ LibcstTransformerPipeline ,
13+ )
14+ from codemodder .codemods .semgrep import SemgrepRuleDetector
1015from codemodder .codemods .transformations .remove_unused_imports import (
1116 RemoveUnusedImportsCodemod ,
1217)
1318from codemodder .codemods .utils import ReplaceNodes
1419from codemodder .codetf import Change
1520from codemodder .dependency import Security
1621from codemodder .file_context import FileContext
17- from core_codemods .api import Metadata , Reference , ReviewGuidance , SimpleCodemod
22+ from core_codemods .api import CoreCodemod , Metadata , Reference , ReviewGuidance
1823
1924replacement_import = "safe_requests"
2025
2126
22- class UrlSandbox (SimpleCodemod ):
23- metadata = Metadata (
24- name = "url-sandbox" ,
25- summary = "Sandbox URL Creation" ,
26- review_guidance = ReviewGuidance .MERGE_AFTER_CURSORY_REVIEW ,
27- references = [
28- Reference (
29- url = "https://github.com/pixee/python-security/blob/main/src/security/safe_requests/api.py"
30- ),
31- Reference (url = "https://portswigger.net/web-security/ssrf" ),
32- Reference (
33- url = "https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html"
34- ),
35- Reference (
36- url = "https://www.rapid7.com/blog/post/2021/11/23/owasp-top-10-deep-dive-defending-against-server-side-request-forgery/"
37- ),
38- Reference (url = "https://blog.assetnote.io/2021/01/13/blind-ssrf-chains/" ),
39- ],
40- )
27+ class UrlSandboxTransformer (LibcstResultTransformer ):
4128 change_description = "Switch use of requests for security.safe_requests"
42-
43- detector_pattern = """
44- rules:
45- - id: url-sandbox
46- message: Unbounded URL creation
47- severity: WARNING
48- languages:
49- - python
50- pattern-either:
51- - patterns:
52- - pattern: requests.get(...)
53- - pattern-not: requests.get("...")
54- - pattern-inside: |
55- import requests
56- ...
57- """
58-
5929 METADATA_DEPENDENCIES = (PositionProvider , ScopeProvider )
60-
6130 adds_dependency = True
6231
6332 def transform_module_impl (self , tree : cst .Module ) -> cst .Module :
@@ -111,7 +80,7 @@ def __init__(
11180 )
11281
11382 def leave_Call (self , original_node : cst .Call ):
114- if not ( self .node_is_selected (original_node ) ):
83+ if not self .node_is_selected (original_node ):
11584 return
11685
11786 line_number = self .node_position (original_node ).start .line
@@ -139,7 +108,7 @@ def leave_Call(self, original_node: cst.Call):
139108 self .changes_in_file .append (
140109 Change (
141110 lineNumber = line_number ,
142- description = UrlSandbox .change_description ,
111+ description = UrlSandboxTransformer .change_description ,
143112 )
144113 )
145114
@@ -156,7 +125,7 @@ def leave_Call(self, original_node: cst.Call):
156125 self .changes_in_file .append (
157126 Change (
158127 lineNumber = line_number ,
159- description = UrlSandbox .change_description ,
128+ description = UrlSandboxTransformer .change_description ,
160129 )
161130 )
162131
@@ -175,3 +144,43 @@ def find_single_assignment(self, node: CSTNode) -> Optional[CSTNode]:
175144 if len (assignments ) == 1 :
176145 return next (iter (assignments )).node
177146 return None
147+
148+
149+ UrlSandbox = CoreCodemod (
150+ metadata = Metadata (
151+ name = "url-sandbox" ,
152+ summary = "Sandbox URL Creation" ,
153+ review_guidance = ReviewGuidance .MERGE_AFTER_CURSORY_REVIEW ,
154+ references = [
155+ Reference (
156+ url = "https://github.com/pixee/python-security/blob/main/src/security/safe_requests/api.py"
157+ ),
158+ Reference (url = "https://portswigger.net/web-security/ssrf" ),
159+ Reference (
160+ url = "https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html"
161+ ),
162+ Reference (
163+ url = "https://www.rapid7.com/blog/post/2021/11/23/owasp-top-10-deep-dive-defending-against-server-side-request-forgery/"
164+ ),
165+ Reference (url = "https://blog.assetnote.io/2021/01/13/blind-ssrf-chains/" ),
166+ ],
167+ ),
168+ detector = SemgrepRuleDetector (
169+ """
170+ rules:
171+ - id: url-sandbox
172+ message: Unbounded URL creation
173+ severity: WARNING
174+ languages:
175+ - python
176+ pattern-either:
177+ - patterns:
178+ - pattern: requests.get(...)
179+ - pattern-not: requests.get("...")
180+ - pattern-inside: |
181+ import requests
182+ ...
183+ """
184+ ),
185+ transformer = LibcstTransformerPipeline (UrlSandboxTransformer ),
186+ )
0 commit comments