swagger-api / swagger-api/swagger-codegen

[Python] api_client.py __deserialize_file() deliberately subverts mkstemp() race condition protection

Open
#3,802 0 comments 0 reactions 0 assignees View on GitHub

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
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

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 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.