PerlDancer / PerlDancer/Dancer2

send_file: quote/semicolon injection into Content-Disposition filename

Open Beginner friendly
#1,805 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Bug
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.