safe-redirect
Ast Rule: function definition
safe-redirect
function visit(node, filename, code) {
if (!useImportFrom(node.context.imports, "django.http", "HttpResponseRedirect") && !useImportFrom(node.context.imports, "django.http", "HttpResponse")) {
return;
}
if (!node.parameters) {
return;
}
if (node.parameters.values.length !== 1) {
return;
}
const firstParameterName = node.parameters.values[0].name;
if (firstParameterName.astType !== "string") {
return;
}
const requestVariableName = firstParameterName.value;
const userVariablesFromRequest = [];
const responsesVariables = [];
const checkRedirectCall = (element, variables) => {
if (element.astType === "return") {
checkRedirectCall(element.value, variables);
}
if (element.astType === "assignment") {
checkRedirectCall(element.right, variables);
}
if (element.astType === "functioncall") {
if (element.functionName.value === "HttpResponseRedirect") {
if (element.arguments.values && element.arguments.values.length === 1) {
const firstArgument = element.arguments.values[0].value;
if (firstArgument.astType === "string" && variables.includes(firstArgument.value)) {
const error = buildError(element.start.line, element.start.col,
element.end.line, element.end.col,
"do not use user-input", "CRITICAL", "SECURITY");
const edit = buildEditUpdate(firstArgument.start.line, firstArgument.start.col, firstArgument.end.line, firstArgument.end.col, `url_for(${firstArgument.value})`);
addError(error);
}
}
}
}
};
node.content.elements && node.content.elements.forEach(e => {
console.log(e.astType);
// First, find variables inferred from the requests
if (e.astType === "assignment") {
if (e.left.astType === "string" && e.right.astType === "functioncall" && e.right.functionName.value === "get" && e.right.moduleOrObject && e.right.moduleOrObject.value === `${requestVariableName}.GET`) {
userVariablesFromRequest.push(e.left.value);
console.log(`pushing ${e.left.value}`);
}
}
// Check if we build a response object
if (e.astType === "assignment") {
if (e.left.astType === "string" && e.right.astType === "functioncall" && e.right.functionName.value === "HttpResponse") {
console.log("pushing");
console.log(e.left.value);
responsesVariables.push(e.left.value);
}
}
// Check if we assign to a response
if (e.astType === "assignment" && e.left.astType === "variableindex" && e.right.astType === "string" && userVariablesFromRequest.includes(e.right.value)) {
const vi = e.left;
if (responsesVariables.includes(vi.variable.value) && vi.index.value === "'Location'") {
const error = buildError(e.start.line, e.start.col,
e.end.line, e.end.col,
"do not use user-input", "CRITICAL", "SECURITY");
addError(error);
}
}
// check if we have a redirect call
checkRedirectCall(e, userVariablesFromRequest);
});
}
error.py
Expected test result: no error