PerlDancer / PerlDancer/Dancer2
send_file: quote/semicolon injection into Content-Disposition filename
Nobody has claimed this yet.
- Dominant language
- Perl
- Stars
- 604
- Forks
- 288
- Avg merge
- 1d 5h
- Merged PRs (30d)
- 5
Description
Severity: medium · Status: reasoned from code (not reproduced end-to-end)
lib/Dancer2/Core/App.pm:1211-1213:
( exists $options{filename} )
and $self->response->header( 'Content-Disposition' =>
($options{content_disposition} || "attachment") . "; filename=\"$options{filename}\"" );
$options{filename} is interpolated into a quoted-string header parameter with no escaping of " or ;. send_file($path, filename => params->{name}) is a common pattern, so a filename of:
x"; something="y
breaks out of the quoted string and injects additional header parameters.
Impact
An attacker who influences the filename option can alter the disposition, spoof the download filename, or append parameters to the header. Requires the application to pass user-controlled data as filename, which is why this is medium rather than high.
Suggested fix
if ( exists $options{filename} ) {
my $filename = $options{filename};
# A filename reaching here is frequently user-supplied. Strip control
# characters, then backslash-escape the two characters that can end the
# quoted-string early and start injecting further parameters.
$filename =~ s/[[:cntrl:]]//g;
$filename =~ s/(["\\])/\\$1/g;
$self->response->header( 'Content-Disposition' =>
( $options{content_disposition} || 'attachment' )
. qq{; filename="$filename"} );
}
Optionally add an RFC 5987 filename*=UTF-8''<pct-encoded> parameter alongside, for non-ASCII filenames — these currently pass through as raw bytes.
Suggested test
send_file with filename => 'x"; injected="y' produces exactly one filename parameter in the emitted header.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in lib/Dancer2/Core/App.pm at lines 1211-1213 and trace the send_file path that builds the Content-Disposition header. Add coverage for a filename such as x"; injected="y and verify the emitted header contains one safely quoted filename parameter, including the stated control-character behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- perl
- Domain
- backend, security
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 84/100