Skip to content
Merged
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 @@ -52,7 +52,9 @@ VALUES (
'persist_uploaded_file',
2,
'destination_folder',
'Optional. Path to the folder where the file will be saved, relative to the web root (the root folder of your website files). By default, the file will be saved in the `uploads` folder.',
'Optional. Path to the folder where the file will be saved, relative to the web root (the root folder of your website files). By default, the file will be saved in the `uploads` folder.

**Security note**: this value must be a folder name you choose yourself in your SQL code (a trusted constant). Never build it from untrusted input such as a form field, a query parameter, a request header, or anything else the visitor controls. The folder is joined directly to the web root, so a value containing `..` or an absolute path would cause the uploaded file to be written *outside* the web root, anywhere the SQLPage process can write. Keeping `destination_folder` a fixed value chosen by the application author avoids this.',
'TEXT'
),
(
Expand Down
7 changes: 6 additions & 1 deletion src/webserver/database/sqlpage_functions/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,12 @@ async fn persist_uploaded_file<'a>(
let exts = allowed_extensions.collect::<Vec<_>>().join(", ");
anyhow::bail!("file extension {extension} is not allowed. Allowed extensions: {exts}");
}
// resolve the folder path relative to the web root
// Resolve the folder path relative to the web root.
// `folder` is trusted application input: it is expected to be a constant chosen by the
// app author in their SQL code, never attacker-controlled request data. It is joined
// directly to the web root, so a `folder` containing `..` or an absolute path would let
// the caller write the uploaded file outside the web root. Callers must not pass
// untrusted input (form fields, query parameters, headers, ...) as the folder.
let web_root = &request.app_state.config.web_root;
let target_folder = web_root.join(&*folder);
// create the folder if it doesn't exist
Expand Down
Loading