mitmproxy / mitmproxy/mitmproxy

curl and httpie export change the body when it has % or a trailing newline

Open
#8,425 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
45.1k
Forks
4.7k
Avg merge
21h 12m
Merged PRs (30d)
16

Description

Problem Description

The curl and httpie export changes the request body when the body has a control character (for example a newline) together with %, a backslash, or a newline at the end. The exported command sends different bytes than the original request.

The body is passed as "$(printf '...')". printf treats % as a format directive and \n, \t and other backslash sequences as escapes. $(...) also removes newlines at the end of the output.

I ran the exported commands in bash against a local server and compared the bytes:

body in mitmproxy exported server received
{"a":1}\n -d "$(printf '{"a":1}\x0a')" {"a":1} (newline lost)
a=100%\nb=2 -d "$(printf 'a=100%\x0ab=2')" a=100 and printf: '\': invalid format character
C:\new\temp\nx (two backslashes) -d "$(printf 'C:\new\temp\x0ax')" C:<LF>ew<TAB>emp<LF>x

A JSON body that ends with a newline is very common, so the first case happens a lot.

Steps to reproduce the behavior:
  1. Capture a POST request whose body is {"a":1} followed by a newline.
  2. Run export.clip curl @focus (or :export.clip curl @focus in the console) and paste the command into bash.
  3. The server gets {"a":1} without the newline. With a body like a=100% followed by a newline the server gets only a=100.

Bodies without control characters are fine, they go through shlex.quote.

A fix is to use ANSI-C quoting ($'...') instead of printf. It expands \xNN byte for byte and does not touch %. I tested it in bash and zsh, all bodies above arrive unchanged. I will open a pull request.

System Information
Mitmproxy: 13.0.0.dev (+79, commit 2ac5b08)
Python:    3.14.6
OpenSSL:   OpenSSL 3.5.5 27 Jan 2026
Platform:  macOS-26.5.2-arm64-arm-64bit-Mach-O

The printf code is unchanged since 11.1.0 (#7520), so the latest release is affected too.

Checklist

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 at the curl and httpie export paths invoked by export.clip curl @focus or :export.clip curl @focus in the console, then reproduce the examples against a local server and compare received bytes. Check the existing printf and shlex.quote handling; done means exported commands preserve percent signs, backslashes, control characters, and trailing newlines in bash and zsh.

Written by the indexing model from the issue text.

Assessment

Tech stack
bash, python, zsh
Domain
cli, tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.