swagger-api / swagger-api/swagger-codegen
[Python] api_client.py __deserialize_file() deliberately subverts mkstemp() race condition protection
Nobody has claimed this yet.
- Dominant language
- Mustache
- Stars
- 17.8k
- Forks
- 6k
- PR merge metrics
- No merged PRs in 30d
Description
Description
Looking at the function __deserialize_file() in the generated api_client.py it uses Python's tempfile.mkstemp() in the least secure way possible. Specifically, it creates a secure tempfile, closes it, deletes it, and opens a new one with potentially the same name to write to. This opens a way that an unprivileged attacker on the same system could get access to the file that is being downloaded (on Linux at least):
If __deserialize_file() will create a tempfile with a random name (which is only readable by the creator), then delete it so it can maybe create a new file . An attacker could then create a file with the same name that is readable by themselves and writeable by anyone. __deserialize_file() then opens and writes its data into that file, and the attacker can read it.
Swagger-codegen version
Swagger-editor version version 2.10.3 (the one on the swagger.io website as of Sept 14, 2016)
Related info
- https://docs.python.org/3/library/tempfile.html?highlight=mkstemp#tempfile.mkstemp
- http://linux.die.net/man/3/mktemp under "BUGS"
Suggest a Fix
Use tempfile.mkstemp properly, either by creating a tempfile file with a given prefix or suffix:
prefix = ""
content_disposition = response.getheader("Content-Disposition")
if content_disposition:
filename = re.\
search(r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition).\
group(1)
prefix =filename
fd, path = tempfile.mkstemp(dir=config.temp_folder_path, prefix=prefix)
fd.write(response.data)
fd.close()
Or if you don't want to mangle the filename, use mkdtemp to create a secure temp directory to put the file in:
dirpath = tempfile.mkdtemp(dir=config.temp_folder_path)
content_disposition = response.getheader("Content-Disposition")
if content_disposition:
filename = re.\
search(r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition).\
group(1)
filepath = os.path.join(dirpath, filename)
else:
filepath = os.path.join(dirpath, generate_file_name_however_you_want())
with open(filepath, 'w'):
f.write(response.data)
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 the generated api_client.py function __deserialize_file() and review Python's tempfile.mkstemp() behavior using the linked documentation. Trace how the temporary file is created, closed, removed, and reopened, then ensure downloaded data is written without reopening a replaced path. Done means the temporary file remains protected from another process while preserving the intended downloaded-file behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- security
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100