Back to skill

Security audit

Django Project Creator

Security checks for vulnerabilities and agentic risk

Overview

This looks like a Django project scaffolding helper, but it runs shell commands built from user-entered names and paths, which can execute unintended local commands.

Review this before installing or running. Only use it in a disposable directory with trusted inputs, and preferably fix it first by replacing shell-string os.system calls with subprocess argument lists, validating Django identifiers, using pathlib for paths, and adding overwrite confirmations. I did not find evidence of exfiltration or persistence, so this is Review rather than malicious.

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

T09 · Insecure Skill Coding Practices

Error
Location
scriptBackend.py:141
Finding
Shell Command Injection Through Unsanitized Project Parameters<![CDATA[ ## Vulnerability Details **File Location**: `scriptBackend.py`, lines 141–160 **Vulnerability Type**: OS command injection **Risk Level**: High ### Vulnerable Code ```python path = input(f'{color.YELLOW}Desired path of this project: {color.END}') 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 commands executed by `os.system`. This function invokes a system shell, so shell metacharacters contained in those values are interpreted as command syntax rather than literal argument content. The existence check on `path` does not make it safe for shell use. A valid path can still contain shell metacharacters. No equivalent validation is performed for project or application names. In addition to command injection, the absence of argument-safe execution causes ordinary paths containing spaces or other shell-sensitive characters to behave incorrectly. The `source .venv/bin/activate` command also executes in a temporary child shell. Its environment changes do not persist into subsequent commands, so later package operations may affect the invo ...[truncated 1159 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Replace every `os.system` invocation involving dynamic data with `subprocess.run` using an argument list and `check=True`. - Validate Django project and application names with a strict Python-identifier allowlist, such as `^[A-Za-z_][A-Za-z0-9_]*$`, and reject Python keywords. - Resolve and manipulate paths using `pathlib.Path`; do not construct paths through raw string concatenation. - Invoke virtual-environment tools directly rather than attempting to activate the environment in a child shell. - Report subprocess failures instead of suppressing them or continuing after unsuccessful setup operations. Example: ```python import keyword import re import subprocess from pathlib import Path IDENTIFIER = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$") def validate_identifier(value): if not IDENTIFIER.fullmatch(value) or keyword.iskeyword(value): raise ValueError("Invalid Django identifier") return value base_path = Path(path).resolve() projectName = validate_identifier(projectName) appName = validate_identifier(appName) venv_python = base_path / ".venv" / "bin" / "python" subprocess.run( [str(venv_python), "-m", "django", "startproject", projectName], cwd=base_path, check=True, ) subprocess.run( [str(venv_python), "manage.py", "startapp", appName], cwd=base_path / projectName, check=True, ) ``` ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scriptBackend.py:124
Finding
Shell and Generated Python Code Injection Through Model Names<![CDATA[ ## Vulnerability Details **File Location**: `scriptBackend.py`, lines 124–132 **Vulnerability Type**: OS command injection and generated source-code 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('../') ``` ### Technical Analysis Each user-provided model name is embedded directly into a shell command passed to `os.system`. Shell metacharacters and command substitutions in a model name can therefore be evaluated immediately by the shell. The same untrusted input is also inserted into generated Python source. A crafted value capable of breaking the intended class declaration can introduce attacker-controlled Python statements into `models.py`. Such code may execute later when Django imports the model module during migrations, application startup, testing, or request handling. This creates two execution opportunities: 1. Immediate operating-system command execution during scaffolding. 2. Delayed Python code execution when the poisoned generated module is imported. ### Attack Path 1. The user selects the model-configuration option. 2. A malicious model-name value containing shell syntax or Python source-breaking content is entered. 3. The value is interpolated into the `echo` command. 4. Shell syntax can execute immediately under the script user's account. 5. Any injected Python content written successfully to `models.py` remains in the generated project. 6. The subsequent migration commands or a later Django process imports the model module, potentially executing the injected Python payload. ### Impact As ...[truncated 671 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Never use shell `echo` to generate source files. - Validate every model name with `str.isidentifier()` and reject Python keywords using `keyword.iskeyword()`. - Consider enforcing Django naming conventions with a stricter regular expression. - Write generated source through Python file APIs with an explicit encoding. - Generate source from fixed templates where only a previously validated identifier can be substituted. - Prefer Django-aware code-generation libraries or an abstract syntax tree generator if generation becomes more complex. - Validate the completed generated source with `ast.parse` before running migrations. - Stop execution if any supplied model name is invalid. Example: ```python import ast import keyword from pathlib import Path for module in splitted: module = module.strip() if not module.isidentifier() or keyword.iskeyword(module): raise ValueError(f"Invalid model name: {module!r}") generated = ( f"class {module}(models.Model):\n" " name = models.CharField(max_length=255, unique=True)\n\n" " def __str__(self):\n" " return self.name\n\n" ) ast.parse(generated) models_file = Path(appName) / "models.py" with models_file.open("a", encoding="utf-8") as file: file.write(generated) ``` ]]>

T08 · Insecure Dependencies

Warning
Location
scriptBackend.py:72
Finding
Unpinned Runtime Installation of Third-Party Dependencies<![CDATA[ ## Vulnerability Details **File Location**: `scriptBackend.py`, lines 72–74 and line 151 **Vulnerability Type**: Insecure and non-reproducible dependency installation **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 os.chdir(path) os.system('source .venv/bin/activate') run_command('pip install django') ``` ### Technical Analysis The script installs mutable package versions at runtime without exact version constraints, a lockfile, integrity hashes, or verification of the configured package source. The effective dependency set can consequently change between executions. `pip` also honors local and user configuration, environment variables, and configured package indexes. If the execution environment points to an untrusted or compromised package index, the script may install attacker-controlled package content. Additionally, `source .venv/bin/activate` executes in a separate child shell and cannot change the parent Python process environment. The subsequent `pip` command may therefore target a global or user-level Python installation rather than the virtual environment the script claims to use. No specific malicious package is present in the reviewed project. The risk arises from unsafe dependency resolution and installation practices. ### Attack Path 1. The script is executed with network access. 2. The local `pip` configuration or environment directs dependency resolution to an untrusted index, or an unreviewed future package release is selected. 3. The script requests the latest matching version because no exact version or integrity hash is specified. 4. `pip` downloads and installs the selected package and its transitive dependencies. 5. Package installation or later import executes package-controlled code in the user's environment. 6. ...[truncated 732 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin reviewed package versions rather than requesting unconstrained latest releases. - Maintain a lockfile containing the complete transitive dependency graph. - Use hash verification, such as pip requirements generated with `--generate-hashes`, and install with `--require-hashes`. - Use an explicitly trusted package index and document its expected configuration. - Invoke the virtual environment's Python executable directly; do not rely on `source`. - Use `python -m pip` to ensure that pip belongs to the intended interpreter. - Fail closed when dependency installation fails and display actionable error information. - Regularly review and update pinned dependencies through a controlled dependency-update process. Example: ```python from pathlib import Path import subprocess venv_python = Path(path) / ".venv" / "bin" / "python" subprocess.run( [ str(venv_python), "-m", "pip", "install", "--require-hashes", "-r", "requirements.lock", ], check=True, ) ``` A reviewed lockfile should contain exact versions and hashes for Django, Django REST Framework, nested routers, CORS headers, and all transitive dependencies. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
Findings (30)

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-flow command injection: appName originates from input() and reaches os.system inside a shell command that writes urls.py. Because the script is an interactive project scaffolder, users are expected to supply these values, which makes exploitability practical rather than theoretical.

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 user-input-to-shell sink where appName flows into os.system. The skill context increases danger because the script is intended to be run locally by developers, giving successful injection direct code execution on their workstation or CI environment.

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 direct tainted-flow vulnerability from path input into os.system. In the context of a developer utility, the script is likely run with the user's normal filesystem permissions, so a successful injection can execute arbitrary local commands and modify source code or secrets.

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
projectName from input() is passed into a shell command that invokes django-admin startproject. Any shell metacharacter in projectName can break command boundaries and execute arbitrary commands, leading to full compromise of the executing user's 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
100% confidence
Finding
appName is directly tainted from user input and reaches a shell execution sink unchanged. This is straightforward command injection and can be exploited with minimal attacker control over the interactive input.

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.

Missing User Warnings

High
Confidence
96% confidence
Finding
The helper functions use shell redirection and file writes to recreate urls.py, views.py, and serializers.py, which can destroy existing content. There is no confirmation prompt or explicit warning that these operations are destructive to pre-existing files.

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 comes from user input, into a command string passed to os.system. An attacker can supply shell metacharacters in the app name to execute arbitrary commands on the host while the script is generating Django files.

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 command again embeds user-supplied appName inside a shell command string. Because os.system invokes a shell, crafted input can break out of the intended echo statement and run arbitrary commands on the machine.

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 inserted into a shell echo command that appends Python code to models.py. An attacker can inject shell syntax to execute arbitrary commands, and can also inject malicious Python source into the generated application.

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 variable is user-controlled and embedded in an os.system call for virtualenv creation. A crafted path containing command separators or subshell syntax can result in arbitrary command execution on the host.

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 os.system('django-admin startproject ...'). A malicious project name containing shell metacharacters can trigger arbitrary command execution under the privileges of the user running the script.

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 attacker-controlled appName into an os.system call. An adversary can exploit this to execute arbitrary shell commands instead of merely creating a Django app.

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.

Vague Triggers

Medium
Confidence
87% confidence
Finding
The skill description is very broad and markets automatic environment provisioning and project bootstrapping without clearly defining when the skill should activate or what inputs and boundaries govern its behavior. In an agent ecosystem, vague trigger scope can cause the skill to be invoked in unintended contexts, leading to overbroad actions such as provisioning environments or applying defaults when the user did not explicitly request them.

Context-Inappropriate Capability

Medium
Confidence
82% confidence
Finding
No manifest is available, so the skill's intended purpose is unknown. Across the file, the code changes directories, installs packages, creates virtual environments, starts Django projects/apps, runs migrations, and writes source files via shell commands, which are broad system-modifying capabilities that are not justified by any declared purpose.

Tainted flow: 'projectName' from input (line 157, user input) → open (file write)

Medium
Category
Data Flow
Content
lines.insert(index, f'\t\'{appName}\'\n')
            lines.insert(index, '\t\'rest_framework\',\n')
            break
    with open(f'../{projectName}/settings.py', 'w') as f:
        f.writelines(lines)
    os.system('touch urls.py')
    os.system('touch serializers.py')
Confidence
84% confidence
Finding
projectName influences the path used for writing settings.py, creating a path traversal or arbitrary file overwrite risk if malicious values such as ../ segments are accepted. Although the script appears aimed at local scaffolding, overwriting attacker-chosen files on the host can still damage the environment or plant malicious configuration.

Static analysis

No suspicious patterns detected.