Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ private import semmle.python.dataflow.new.DataFlow
private import semmle.python.Concepts
private import semmle.python.dataflow.new.RemoteFlowSources
private import semmle.python.dataflow.new.BarrierGuards
private import semmle.python.ApiGraphs

/**
* Provides default sources, and sinks for detecting
Expand Down Expand Up @@ -105,4 +106,14 @@ module PathInjection {
class SanitizerFromModel extends Sanitizer {
SanitizerFromModel() { ModelOutput::barrierNode(this, "path-injection") }
}

/**
* A call to `django.utils._os.safe_join`, which validates that the resulting path
* stays within the base directory, considered as a sanitizer.
*/
class DjangoSafeJoinSanitizer extends Sanitizer {
DjangoSafeJoinSanitizer() {
this = API::moduleImport("django").getMember("utils").getMember("_os").getMember("safe_join").getACall()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from django.utils._os import safe_join
from flask import Flask, request # $ Source

app = Flask(__name__)

MEDIA_ROOT = "/var/www/media"


@app.route("/file")
def serve_file():
filename = request.args.get("filename", "") # user input
# safe_join validates the path stays within MEDIA_ROOT
safe_path = safe_join(MEDIA_ROOT, filename)
open(safe_path) # Safe - no alert expected


@app.route("/file_unsafe")
def serve_file_unsafe():
filename = request.args.get("filename", "") # user input
unsafe_path = MEDIA_ROOT + "/" + filename
open(unsafe_path) # $ Alert
Loading