Runtime cache does not enforce Project directory permissions and ownership

Open
#114 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
52/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
django, python
Domain
backend, security

Research direction

Start by reading netbox_scripts/runtime/cache.py, especially _ensure_private_root() and materialize_revision(), then inspect the storage code used by store.write_revision(). Reproduce the reported umask and permissive-directory cases and check the Project, staging, and lock file modes and ownership. Done means new directories and lock files have private permissions, unsafe existing Project directories are rejected, and a verified published revision cannot be replaced.

Written by the indexing model from the issue text.

Description

app: scripts Bucket: KTLO severity: medium status: backlog type: bug
Plugin Version

v0.0.1

NetBox Version

v4.7.1

Python Version

3.12

Steps to Reproduce

Using one account in NetBox's Django shell (python manage.py shell):

  1. Prepare a valid revision containing example.py and write it to an InMemoryStorage using netbox_scripts.storage.store.write_revision().
  2. Create a temporary cache root and set its permissions to 0755 with chmod().
  3. Set the process umask to 0002 and call netbox_scripts.runtime.cache.materialize_revision() with that root. Restore the previous umask in a finally block.
  4. Inspect <root>/<storage_key>/ and its .<digest>.lock file.
  5. Create a second cache root with permissions 01777. Inside it, create <storage_key>/ and set its permissions to 0777.
  6. Materialize the same revision using the second root.
Expected Behavior

New Project and staging directories are created with private permissions.

Before using an existing Project directory, the plugin checks that it belongs to the NetBox account or root and rejects permissions that let other accounts modify its contents.

The published revision remains protected from replacement after verification.

Observed Behavior

In the first case, the Project directory is created with permissions 0775 and the lock file with 0664. Project and staging directory creation follows the process umask.

In the second case, materialization succeeds inside the existing 0777 Project directory.

Source inspection shows that _ensure_private_root() checks the cache root and its ancestors, but the Project directory is accepted through mkdir(exist_ok=True) without checking its owner or permissions.

When another local account can traverse the cache path, writable Project directories allow it to replace the published revision directory despite the revision's read-only permissions.

The default cache root, when created by the plugin with permissions 0700, prevents other accounts from reaching these directories. The exposure requires a cache location that other accounts can traverse.

Dominant language
Python
Stars
8
Forks
0
Avg merge
11h 41m
Merged PRs (30d)
38

Getting set up

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.

More from netbox-community/netbox-scripts

All issues in netbox-community/netbox-scripts

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.