// CWE-614: Cookie set without security attributes (HttpOnly, Secure, SameSite).
// Only activated when mocket or crescent is imported.
///|
priv struct Cwe614Visitor {
findings : Array[Finding]
file : String
source : String
severity : Severity
}
///|
pub fn cwe614_info() -> RuleInfo {
{
id: { cwe: 614, variant: "cookie-attrs" },
name: "Cookie Missing Security Attributes",
description: "set_cookie() without http_only, secure, or same_site attributes leaves cookies vulnerable to theft and CSRF.",
default_severity: Warning,
}
}
///|
pub fn run_cwe614(
impls : @list.List[@syntax.Impl],
file : String,
source : String,
findings : Array[Finding],
severity : Severity,
) -> Unit {
let visitor : Cwe614Visitor = { findings, file, source, severity }
impls.each(fn(impl_) { @syntax.IterVisitor::visit_Impl(visitor, impl_) })
}
///|
impl @syntax.IterVisitor for Cwe614Visitor with fn visit_Expr_DotApply(
env,
self~,
method_name~,
args~,
return_self~,
loc~,
) {
if method_name.name == "set_cookie" && !is_cookie_value_empty(args) {
let missing : Array[String] = []
if !has_labelled_arg(args, "http_only") {
missing.push("http_only")
}
if !has_labelled_arg(args, "secure") {
missing.push("secure")
}
if !has_labelled_arg(args, "same_site") {
missing.push("same_site")
}
if missing.length() > 0 {
let attrs = missing.iter().map(fn(s) { s }).collect().join(", ")
env.findings.push(
make_finding(
{ cwe: 614, variant: "cookie-attrs" },
env.severity,
Medium,
"set_cookie() missing security attributes: " +
attrs +
". Add these to protect against XSS cookie theft and CSRF.",
env.file,
env.source,
loc,
),
)
}
}
@syntax.IterVisitor::base(env).visit_Expr_DotApply(
self~,
method_name~,
args~,
return_self~,
loc~,
)
}