safe-redirect
Ast Rule: function definition
safe-redirect
function visit(node, filename, code) {
if (!useImportFrom(node.context.imports, "flask", "Response")) {
return;
}
if (!hasDecorator(node, "app.route") && !hasDecorator(node, "route")) {
return;
}
const variablesFromRequests = [];
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 === "redirect") {
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})`);
const fix = buildFix(`add mimetype argument`, [edit]);
addError(error.addFix(fix));
}
}
}
}
};
node.content.elements && node.content.elements.forEach(e => {
// First, find variables inferred from the requests
if (e.astType === "assignment") {
if (e.right.astType === "variableindex") {}
if (e.left.astType === "string" && e.right.astType === "variableindex" && e.right.variable.value.startsWith("request.")) {
variablesFromRequests.push(e.left.value);
}
}
// Check if we build a response object
if (e.astType === "assignment") {
if (e.right.astType === "variableindex") {}
if (e.left.astType === "string" && e.right.astType === "functioncall" && e.right.functionName.value === "Response") {
responsesVariables.push(e.left.value);
}
}
// Check if we assign to a response
if (e.astType === "assignment" && e.left.astType === "variableindex" && e.right.astType === "string" && variablesFromRequests.includes(e.right.value)) {
const vi = e.left;
const possibleValues = responsesVariables.map(r => `${r}.headers`);
if (possibleValues.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, variablesFromRequests);
});
}
no-error.py
Expected test result: no error
error.py
Expected test result: has error