Back to skill

Security audit

Django Project Creator

Security checks for vulnerabilities and agentic risk

Overview

This skill appears to be a Django project scaffolder, but its bundled script can run unintended shell commands from ordinary project-name, app-name, path, or model-name input.

Treat this as a Review item before installing. Only run it in a disposable directory or isolated environment, never with untrusted names or paths, and prefer a revised version that validates Django identifiers, writes files with Python APIs, uses subprocess argument lists, and pins dependencies.

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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
scriptBackend.py:151
Finding
OS Command Injection Through Unvalidated Project Inputs<![CDATA[ ## Vulnerability Details **File Location**: `scriptBackend.py`, lines 151–171 **Vulnerability Type**: OS command injection **Risk Level**: High ### Vulnerable Code ```python if os.path.isdir(path) and os.path.exists(path): answer = input(f'{color.YELLOW}Would you like to create a venv in the desired directory: {color.END}') if answer.lower() == 'yes' or answer.lower() == 'y': os.system(f'python3 -m venv {path}.venv') loading('Creating Virtual Envirement', 1) projectName = input(f'{color.YELLOW}Choose a name for your project: {color.END}') if os.path.exists(f'{path}{projectName}'): print(f'{color.RED}Directory exists !{color.END}') exit(1) os.chdir(path) os.system('source .venv/bin/activate') run_command('pip install django') os.system(f'django-admin startproject {projectName}') os.chdir(f'{path}{projectName}') appName = input(f'{color.YELLOW}Choose a name for your app: {color.END}') os.system(f'django-admin startapp {appName}') ``` ### Technical Analysis The user-controlled `path`, `projectName`, and `appName` values are interpolated directly into strings passed to `os.system()`. This API executes its input through a command shell. Consequently, shell control operators, substitutions, redirections, and other metacharacters in these values are interpreted as command syntax rather than literal arguments. The checks performed on `path` only establish whether the supplied path exists and is a directory. They do not safely quote the value or prevent shell interpretation. No validation is applied to `projectName` or `appName`. ### Attack Path 1. An attacker or untrusted user starts the interactive bootstrap script. 2. The attacker provides a valid base directory. 3. When prompted for a project or application name, the attacker supplies a value containing shell syntax that terminates or extends the intended `django-admin` command. 4. The value is incorporated in ...[truncated 850 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Replace every interpolated `os.system()` call with `subprocess.run()` using an argument list and `check=True`: ```python subprocess.run( [sys.executable, "-m", "venv", str(venv_path)], check=True, ) subprocess.run( [str(venv_python), "-m", "django", "startproject", project_name], check=True, ) ``` - Validate project and application names against Django/Python identifier requirements, for example `^[A-Za-z_][A-Za-z0-9_]*$`. - Reject Python keywords and names that Django does not accept. - Construct paths with `pathlib.Path` rather than string concatenation. - Resolve the target path and verify that generated directories remain beneath the intended base directory. - Do not rely on shell quoting as the primary defense; eliminate shell evaluation entirely. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scriptBackend.py:135
Finding
Shell and Persistent Python Code Injection Through Model Names<![CDATA[ ## Vulnerability Details **File Location**: `scriptBackend.py`, lines 135–147 **Vulnerability Type**: OS command injection and generated-source injection **Risk Level**: High ### Vulnerable Code ```python def CreateModuls(): modulsName = input(f'{color.GREEN}give me all the models (separated by commas for example: model1, model2 ...): {color.END}') splitted = modulsName.split(', ') os.chdir(appName) for module in splitted: os.system(f'''echo "class {module}(models.Model): name = models.CharField(max_length=255, unique=True) def __str__(self): return self.name\n" >> models.py''') os.chdir('../') run_command(f'python3 manage.py makemigrations') run_command(f'python3 manage.py migrate') ``` ### Technical Analysis Every model name is embedded directly into a shell-backed `echo` command without validation. A crafted value can affect the shell command through quoting, command substitution, redirection, or command separators. The value is also inserted into Python source code as a class name. This creates a second injection boundary: a value that changes the generated Python syntax can persist attacker-controlled code in `models.py`. Django imports model modules during management operations and application startup, so malicious generated code may execute later even if immediate shell injection is avoided. ### Attack Path 1. The attacker selects the model-configuration option. 2. The attacker submits one or more crafted model names containing shell syntax or Python source fragments. 3. The script places each value inside the command passed to `os.system()`. 4. Shell syntax can execute immediately with the script user's privileges. 5. Alternatively, injected Python can be appended to `models.py`. 6. The script subsequently runs `makemigrations` and `migrate`, which load Django application modules and may execute the injected Python. 7. Persisted injected code can also execute whenever the generated D ...[truncated 504 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Validate each model name before use: - Require `str.isidentifier()`. - Reject Python keywords with `keyword.iskeyword()`. - Optionally enforce a stricter naming policy such as `^[A-Z][A-Za-z0-9_]*$`. - Generate source files using Python file APIs rather than shell commands: ```python with open("models.py", "a", encoding="utf-8") as model_file: model_file.write(model_template.format(model_name=validated_name)) ``` - Use a trusted template engine or Python abstract-syntax-tree generation when practical. - Never permit arbitrary source fragments in a field intended to contain only an identifier. - Run generated-code validation before migrations, such as parsing it with `ast.parse()`. - Invoke management commands through argument-list subprocess calls with `check=True`. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scriptBackend.py:45
Finding
Unsafe Shell-Based Generation of Django Source Files<![CDATA[ ## Vulnerability Details **File Location**: `scriptBackend.py`, lines 45–75 and 94–119 **Vulnerability Type**: OS command injection through source-file generation **Risk Level**: Medium ### Vulnerable Code ```python def DjangoNoRest(): os.chdir(appName) os.system('touch urls.py') os.system(f'''echo "from django.urls import path from .views import * urlpatterns = [ path('AppRoute/', YOUR_VIEW), ]" > urls.py''') os.system(f'''echo "from django.shortcuts import render # Create your views here. def YOUR_VIEW(request): pass" > views.py ''') os.chdir(f'../{projectName}') searchItem = 'django.contrib.staticfiles' with open('settings.py', 'r') as file: lines = file.readlines() for index, line in enumerate(lines, start=1): if searchItem in line: lines.insert(index, f'\t\'{appName}\'\n') break with open('settings.py', 'w') as f: f.writelines(lines) os.system(f'''echo "from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('{appName}/', include('{appName}.urls')), ]" > urls.py''') ``` The REST setup uses the same pattern: ```python os.system(f'''echo "from rest_framework_nested import routers from .views import * router = routers.DefaultRouter() router.register('UR_ROUTE', ViewSet) urlpatterns = router.urls" > urls.py''') os.system(f'''echo "from rest_framework.viewsets import ModelViewSet from .models import * from .serializers import * class ViewSet(ModelViewSet): pass" > views.py ''') os.chdir(f'../{projectName}') os.system(f'''echo "from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('{appName}/', include('{appName}.urls')), ]" > urls.py''') ``` ### Technical Analysis The script generates source files by constructing multiline shell commands. In particular, `appName` is inserted into shel ...[truncated 1477 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Eliminate `touch` and `echo` shell commands. - Generate files with `Path.touch()`, `Path.write_text()`, or normal `open()` operations. - Validate `appName` as a strict Python identifier before using it in paths or generated code. - Use fixed templates in which only validated identifiers are substituted. - Escape values according to the generated Python context even after identifier validation. - Check for existing files before overwriting them and use explicit encodings. - Consider writing to a temporary file and atomically replacing the destination after successful validation. ]]>

T08 · Insecure Dependencies

Warning
Location
scriptBackend.py:80
Finding
Unpinned Dependency Installation and Ineffective Virtual-Environment Isolation<![CDATA[ ## Vulnerability Details **File Location**: `scriptBackend.py`, lines 80–83 and 151–166 **Vulnerability Type**: Insecure dependency installation and environment confusion **Risk Level**: Medium ### Vulnerable Code ```python def DjangoRest(): os.chdir(appName) run_command('pip install djangorestframework') run_command('pip install drf-nested-routers') run_command('pip install django-cors-headers') ``` ```python if answer.lower() == 'yes' or answer.lower() == 'y': os.system(f'python3 -m venv {path}.venv') loading('Creating Virtual Envirement', 1) projectName = input(f'{color.YELLOW}Choose a name for your project: {color.END}') if os.path.exists(f'{path}{projectName}'): print(f'{color.RED}Directory exists !{color.END}') exit(1) os.chdir(path) os.system('source .venv/bin/activate') run_command('pip install django') os.system(f'django-admin startproject {projectName}') ``` The command helper uses whichever executable is found through the current process environment: ```python def run_command(command): result = subprocess.run(command.split(), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) if result.returncode == 0: print(f'{color.GREEN}Package downloaded successfully{color.END}') else: print(f'{color.RED}Error occured !{color.END}') ``` ### Technical Analysis Dependencies are installed without version constraints or integrity hashes. The effective package version can therefore change between executions based on the configured package index and publication state. The virtual-environment handling is also ineffective. Running `source .venv/bin/activate` in `os.system()` starts a child shell; environment changes in that child cannot modify the parent Python process. Subsequent calls to `pip` and `django-admin` therefore use whichever executables are resolved through the parent process's `PATH`. There is also a path inconsistency: the environment is created as `{path}.venv`, while th ...[truncated 1422 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Define one canonical environment path with `pathlib.Path`. - Invoke the environment's interpreter directly instead of sourcing an activation script: ```python venv_dir = base_path / ".venv" subprocess.run([sys.executable, "-m", "venv", str(venv_dir)], check=True) venv_python = venv_dir / "bin" / "python" subprocess.run( [str(venv_python), "-m", "pip", "install", "--require-hashes", "-r", "requirements.lock"], check=True, ) ``` - On Windows, account for the environment interpreter under `Scripts/python.exe`. - Pin all direct and transitive dependencies to reviewed versions in a lock file. - Add cryptographic hashes and install with `--require-hashes`. - Use a trusted, explicitly configured package index where the deployment model permits it. - Invoke Django through the selected interpreter, such as `venv_python -m django`, rather than relying on ambient `PATH`. - Preserve and report subprocess error output instead of suppressing it completely. - Check subprocess failures with `check=True` and stop setup when installation fails. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (27)

Tainted flow: 'appName' from input (line 169, user input) → os.system (code execution)

Critical
Category
Data Flow
Content
break
    with open('settings.py', 'w') as f:
        f.writelines(lines)
    os.system(f'''echo "from django.contrib import admin
from django.urls import path, include

urlpatterns = [
Confidence
100% confidence
Finding
This is a confirmed tainted data flow from appName input to os.system. In the context of a scaffolding skill that encourages users to enter arbitrary names, this makes exploitation realistic and dangerous because the script is expected to run on a developer workstation with write access.

Tainted flow: 'appName' from input (line 169, user input) → os.system (code execution)

Critical
Category
Data Flow
Content
''')

    os.chdir(f'../{projectName}')
    os.system(f'''echo "from django.contrib import admin
from django.urls import path, include

urlpatterns = [
Confidence
100% confidence
Finding
This is another confirmed appName-to-shell injection path in a code-generation step. Since the script modifies project files automatically, arbitrary command execution here could also tamper with the project, install backdoors, or exfiltrate local data.

Tainted flow: 'path' from input (line 27, user input) → os.system (code execution)

Critical
Category
Data Flow
Content
answer = input(f'{color.YELLOW}Would you like to create a venv in the desired directory: {color.END}')

    if answer.lower() == 'yes' or answer.lower() == 'y':
        os.system(f'python3 -m venv {path}.venv')
        loading('Creating Virtual Envirement', 1)

    projectName = input(f'{color.YELLOW}Choose a name for your project: {color.END}')
Confidence
100% confidence
Finding
This is a confirmed tainted flow from path input into an os.system invocation. Because path values commonly include spaces and shell-significant characters, this is especially easy to misuse and can result in arbitrary command execution before the rest of the project is even created.

Tainted flow: 'projectName' from input (line 157, user input) → os.system (code execution)

Critical
Category
Data Flow
Content
os.chdir(path)
    os.system('source .venv/bin/activate')
    run_command('pip install django')
    os.system(f'django-admin startproject {projectName}')
    os.chdir(f'{path}{projectName}')

    appName = input(f'{color.YELLOW}Choose a name for your app: {color.END}')
Confidence
100% confidence
Finding
This is a direct tainted flow from projectName input to os.system('django-admin startproject ...'). The context increases risk because project setup tools are commonly run by developers with significant local permissions, so successful injection can fully compromise the workstation or CI environment.

Tainted flow: 'appName' from input (line 169, user input) → os.system (code execution)

Critical
Category
Data Flow
Content
appName = input(f'{color.YELLOW}Choose a name for your app: {color.END}')

    os.system(f'django-admin startapp {appName}')

    create = input(f'{color.YELLOW}would you like to create a requirements file: {color.END}')
    if create.lower() == 'yes' or create.lower() == 'y':
Confidence
90% confidence
Finding
External input (network, user) flows to a code execution sink. This enables remote code execution or command injection.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
END = '\033[0m'
   CYAN_BG = '\33[1;37;40m'

os.system('clear')

print(f'''{color.PURPLE}{color.BOLD}
\t                        _           __                          __
Confidence
85% confidence
Finding
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
def DjangoNoRest():
    os.chdir(appName)
    os.system('touch urls.py')
    os.system(f'''echo "from django.urls import path
from .views import *
Confidence
85% confidence
Finding
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
def DjangoNoRest():
    os.chdir(appName)
    os.system('touch urls.py')
    os.system(f'''echo "from django.urls import path
from .views import *
Confidence
85% confidence
Finding
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
def DjangoNoRest():
    os.chdir(appName)
    os.system('touch urls.py')
    os.system(f'''echo "from django.urls import path
from .views import *

urlpatterns = [
Confidence
85% confidence
Finding
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
urlpatterns = [
    path('AppRoute/', YOUR_VIEW),
]" > urls.py''')
    os.system(f'''echo "from django.shortcuts import render

# Create your views here.
def YOUR_VIEW(request):
Confidence
85% confidence
Finding
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
break
    with open('settings.py', 'w') as f:
        f.writelines(lines)
    os.system(f'''echo "from django.contrib import admin
from django.urls import path, include

urlpatterns = [
Confidence
99% confidence
Finding
This shell command interpolates appName, which is taken from user input, into an os.system call. An attacker can supply shell metacharacters in the app name to break out of the intended command and execute arbitrary commands on the host.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
with open(f'../{projectName}/settings.py', 'w') as f:
        f.writelines(lines)
    os.system('touch urls.py')
    os.system('touch serializers.py')
    os.system(f'''echo "from rest_framework_nested import routers
from .views import *
Confidence
85% confidence
Finding
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
f.writelines(lines)
    os.system('touch urls.py')
    os.system('touch serializers.py')
    os.system(f'''echo "from rest_framework_nested import routers
from .views import *

router = routers.DefaultRouter()
Confidence
85% confidence
Finding
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
urlpatterns = router.urls" > urls.py''')

    os.system(f'''echo "from rest_framework.viewsets import ModelViewSet
from .models import *
from .serializers import *
Confidence
85% confidence
Finding
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
''')

    os.chdir(f'../{projectName}')
    os.system(f'''echo "from django.contrib import admin
from django.urls import path, include

urlpatterns = [
Confidence
99% confidence
Finding
This shell command interpolates appName into an os.system call when generating Django URL configuration. Because appName comes from user input, crafted input can trigger arbitrary shell command execution with the privileges of the script runner.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
splitted = modulsName.split(', ')
    os.chdir(appName)
    for module in splitted:
        os.system(f'''echo "class {module}(models.Model):
    name = models.CharField(max_length=255, unique=True)

    def __str__(self):
Confidence
99% confidence
Finding
module values come from user input and are interpolated into a shell echo command that appends to models.py. This creates both command-injection risk and code-generation risk, allowing arbitrary shell execution or malicious Python code insertion into the generated project.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
answer = input(f'{color.YELLOW}Would you like to create a venv in the desired directory: {color.END}')

    if answer.lower() == 'yes' or answer.lower() == 'y':
        os.system(f'python3 -m venv {path}.venv')
        loading('Creating Virtual Envirement', 1)

    projectName = input(f'{color.YELLOW}Choose a name for your project: {color.END}')
Confidence
99% confidence
Finding
The path value is user-supplied and directly inserted into an os.system command for virtual environment creation. Crafted path input can break command boundaries and execute arbitrary OS commands.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
exit(1)
    
    os.chdir(path)
    os.system('source .venv/bin/activate')
    run_command('pip install django')
    os.system(f'django-admin startproject {projectName}')
    os.chdir(f'{path}{projectName}')
Confidence
85% confidence
Finding
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
os.chdir(path)
    os.system('source .venv/bin/activate')
    run_command('pip install django')
    os.system(f'django-admin startproject {projectName}')
    os.chdir(f'{path}{projectName}')

    appName = input(f'{color.YELLOW}Choose a name for your app: {color.END}')
Confidence
99% confidence
Finding
projectName is taken from user input and inserted directly into an os.system command. A malicious project name containing shell metacharacters can execute arbitrary commands, making this a straightforward command injection leading to full code execution on the local system.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
appName = input(f'{color.YELLOW}Choose a name for your app: {color.END}')

    os.system(f'django-admin startapp {appName}')

    create = input(f'{color.YELLOW}would you like to create a requirements file: {color.END}')
    if create.lower() == 'yes' or create.lower() == 'y':
Confidence
99% confidence
Finding
This command directly interpolates appName from user input into a shell command. An attacker can provide a crafted app name to achieve arbitrary command execution during project scaffolding.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Content
create = input(f'{color.YELLOW}would you like to create a requirements file: {color.END}')
    if create.lower() == 'yes' or create.lower() == 'y':
        os.system('pip freeze > requirements.txt')
    
    setup = input(f'{color.YELLOW}you want to set up the files for django ? (yes or no): {color.END}')
Confidence
85% confidence
Finding
os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
No manifest is available, so there is no declared purpose that would justify broad command-execution capabilities. The code clears the terminal, creates virtual environments, invokes django-admin/manage.py, and runs pip installs through os.system/subprocess, which is a powerful capability beyond a minimally justified unknown-purpose skill.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The code creates and overwrites project files such as urls.py, views.py, serializers.py, requirements.txt, and settings.py, and changes directories throughout execution. With no manifest or declared scope, this level of write access is not justified by any stated intent and materially changes local developer projects.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
This code creates and overwrites project files such as urls.py, views.py, settings.py, serializers.py, and requirements.txt, and also creates virtual environments and Django projects. While there are status messages after some actions, there is no clear user-facing warning that the script will modify files and project structure in the selected path before those operations occur.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
The script installs packages with pip, creates a virtual environment, runs django-admin, and executes manage.py commands, all of which change the local environment and system state. Although some success/error messages are printed, the user is not explicitly warned that dependencies will be installed and commands executed on their system.

Static analysis

No suspicious patterns detected.