Back to skill

Security audit

Django Production Engineering

Security checks for vulnerabilities and agentic risk

Overview

This Django guidance skill is mostly coherent, but it includes a production multi-tenant pattern that could break tenant isolation if copied.

Before installing or using this skill, treat its code snippets as templates that require engineering review. Do not copy the multi-tenant TenantMiddleware or TenantManager pattern as written; tenant access should be authorized through authenticated membership and fail closed. Pin build tools in Docker examples and require explicit review before applying generated deployment, authentication, CI/CD, or data-access changes.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:1078
Finding
Broken Tenant Isolation in Recommended Multi-Tenant Pattern<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:1078-1099` **Vulnerability Type**: Tenant authorization bypass and ineffective queryset isolation **Risk Level**: High ### Vulnerable Code ```python # Middleware: set tenant from request class TenantMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): tenant_id = request.headers.get("X-Tenant-ID") if tenant_id: request.tenant = Tenant.objects.get(id=tenant_id) return self.get_response(request) # Auto-filter all queries by tenant class TenantManager(models.Manager): def get_queryset(self): from threading import local _thread_local = local() qs = super().get_queryset() tenant = getattr(_thread_local, "tenant", None) if tenant: qs = qs.filter(tenant=tenant) return qs ``` ### Technical Analysis The middleware trusts the client-controlled `X-Tenant-ID` header and retrieves the corresponding tenant without verifying that the authenticated user is authorized to access it. This allows a caller to attempt tenant selection using an arbitrary tenant identifier. The advertised automatic filtering mechanism is also ineffective. `TenantManager.get_queryset()` creates a new `threading.local()` object every time it is called. No tenant value is written to this new object, and it has no connection to `request.tenant`. Consequently, `tenant` is normally `None`, the conditional filter is skipped, and the unscoped base queryset is returned. This violates the central security requirement of a multi-tenant application: tenant boundaries must be enforced through authenticated authorization and fail-closed data scoping. Although this is documentation rather than directly executable project code, the Skill presents the pattern as reusable production guidance. Applications generated from or modeled on it could therefore inherit the vulnerabilit ...[truncated 1397 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Never authorize tenant access solely from a client-provided identifier. 2. Resolve the requested tenant through an authenticated membership relationship, for example: ```python tenant = request.user.tenants.filter(id=tenant_id).first() if tenant is None: raise PermissionDenied("User is not authorized for this tenant.") request.tenant = tenant ``` 3. Fail closed when the tenant header or authenticated tenant context is missing. Do not return an unfiltered queryset. 4. Avoid creating a new `threading.local()` instance inside `get_queryset()`. If implicit request context is unavoidable, use a correctly managed `contextvars.ContextVar` that is set and reset by middleware. 5. Prefer explicit tenant-scoped service and queryset APIs, such as `Model.objects.for_tenant(request.tenant)`, so the security boundary is visible and testable. 6. Apply object-level authorization in addition to queryset filtering. 7. Validate that related-object lookups, bulk operations, background tasks, and administrative interfaces also enforce the same tenant boundary. 8. Add negative tests proving that a user from tenant A cannot read, update, or delete tenant B's records, including when tenant headers are omitted, altered, or malformed. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:979
Finding
Unpinned Build Tool Creates Mutable Supply-Chain Input<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:979` **Vulnerability Type**: Unpinned third-party build dependency **Risk Level**: Medium ### Vulnerable Code ```dockerfile RUN pip install --no-cache-dir uv ``` ### Technical Analysis The production Dockerfile example installs `uv` without specifying an exact version or verifying a package hash. Every image build therefore resolves whichever release the configured Python package index considers current at that time. This makes builds non-reproducible and allows upstream changes to enter the build without code review. Because package installation executes package build and installation logic, a compromised package release, compromised package index, or incompatible future release could affect the resulting image. The command runs before the Dockerfile switches to the unprivileged `app` user, so installation occurs with root privileges inside the builder stage. There is no evidence that `uv` itself is malicious. The finding concerns unsafe dependency selection and integrity controls in production guidance. ### Attack Path 1. A developer copies the documented production Dockerfile. 2. The build environment resolves `uv` from its configured package index without a version or hash constraint. 3. An upstream account, release pipeline, package index, or dependency distribution channel is compromised, or a future incompatible release is published. 4. A subsequent container build automatically downloads the affected release. 5. Package installation code executes with root privileges in the builder stage. 6. Malicious or unintended artifacts may be introduced into the build output copied into the runtime image. 7. The altered application image is deployed if the CI/CD process does not independently detect the change. ### Impact Assessment A successful supply-chain compromise could affect the confidentiality and integrity of source code, build credentials, generated artifacts, and deployed applicat ...[truncated 400 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `uv` to an explicitly reviewed version: ```dockerfile RUN pip install --no-cache-dir "uv==<reviewed-version>" ``` 2. Where supported, require a verified package hash: ```text uv==<reviewed-version> \ --hash=sha256:<verified-distribution-hash> ``` 3. Install from a locked requirements file using `pip install --require-hashes`. 4. Use a controlled internal package mirror or an approved artifact repository. 5. Add dependency scanning and provenance verification to CI. 6. Update the pinned version through a reviewed dependency-update process rather than implicitly during every build. 7. Avoid exposing production secrets as Docker build arguments or environment variables during dependency installation. ]]>
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (2)

Vague Triggers

Medium
Confidence
90% confidence
Finding
The quick-start section uses very broad natural-language trigger phrases such as "Review this Django project" and "Production checklist," which can easily overlap with ordinary user requests in unrelated contexts. In agent platforms that auto-route or auto-activate skills based on prompt similarity, this increases the chance of unintended invocation, causing the skill to steer outputs, expose internal project context to the skill, or interfere with higher-priority instructions.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The skill exposes very broad natural-language triggers such as 'Review this Django project', 'Deploy this Django app', and 'Set up authentication' without defining clear activation boundaries, required confirmations, or exclusions. In an agent setting, this can cause overbroad execution or generation of sensitive operational guidance from loosely matched prompts, increasing the risk of unintended actions, unsafe changes, or misuse in higher-privilege contexts.

Static analysis

No suspicious patterns detected.