Here is the combined list of vulnerabilities in markdown format:
-
Vulnerability Name: Command Injection in Precompiler Commands
-
Description:
- An attacker, assuming they can influence Django settings (e.g., through a separate vulnerability or misconfiguration), modifies the
COMPRESS_PRECOMPILERSsetting insettings.py. This setting defines external precompiler commands for various file types. - The attacker injects a malicious command into the command template string of one of the precompilers. For example, they might configure a precompiler to execute a command like
touch /tmp/pwned; {infile} {outfile}for a specific mimetype. This command template is sourced from the configuration settings and is formatted using Python’s string formatting. - The attacker then triggers a scenario where django-compressor processes a file (either a legitimate file or a crafted one) that is associated with the mimetype they configured with the malicious command. This can be achieved by including a file of the configured mimetype within a
{% compress %}block in a Django template. For example, rendering a Django template that includes a<style type="text/x-exploit">block if 'text/x-exploit' is configured as the vulnerable mimetype. - When django-compressor processes this file, the
CompilerFilterclass in/code/compressor/filters/base.pyis invoked. Theinputmethod of this class formats the command string usingself.command.format(**options), whereoptionscan include placeholders like{infile}and{outfile}, and executes it usingsubprocess.Popenwithshell=True. - While file path parameters (
{infile}and{outfile}) are shell-quoted on non-Windows platforms, other placeholders or the command template itself are not sanitized. If an attacker controls these unsanitized configuration values, they can inject arbitrary shell commands. - The injected command is executed on the server due to
shell=True, leading to arbitrary code execution with the privileges of the Django application process.
- An attacker, assuming they can influence Django settings (e.g., through a separate vulnerability or misconfiguration), modifies the
-
Impact:
- Remote Code Execution (RCE): Successful exploitation allows the attacker to execute arbitrary commands on the server hosting the Django application. This can lead to a complete compromise of the server, including unauthorized data access, data manipulation, service disruption, and the potential to pivot to internal networks. The attacker can gain full control over the server environment.
-
Vulnerability Rank: critical
-
Currently Implemented Mitigations:
- Partial Mitigation: File path parameters (i.e.,
{infile}and{outfile}) are passed throughshlex.quoteon non-Windows platforms before being substituted into the command template. This offers some protection against command injection via filenames. - Reliance on Secure Configuration: The system relies on the assumption that
COMPRESS_PRECOMPILERSand other related settings are defined and managed only by trusted developers using secure, hard-coded configuration values. It assumes that these settings are not influenced by untrusted user input.
- Partial Mitigation: File path parameters (i.e.,
-
Missing Mitigations:
- Input Sanitization: Implement comprehensive input sanitization for all parts of the command strings and any options used in
CompilerFilter, not just file paths. This should include validating or sanitizing all placeholders in the command template and dynamically supplied arguments. - Avoid
shell=True: ModifyCompilerFilterto avoid usingshell=Trueinsubprocess.Popen. Instead, execute commands directly as a list of arguments. This would require refactoring how precompiler commands are defined and used to ensure commands are executed safely without shell interpretation. - Command Whitelisting or Validation: Implement a whitelist or validation mechanism to ensure that the final resolved command matches an approved “safe” pattern. This could involve parsing the command and verifying its structure before execution.
- Defense-in-Depth: Implement defense-in-depth measures such as executing precompiler commands in a restricted privilege sandbox, chroot, or similar container to limit the impact of successful command injection.
- Documentation and Warnings: Enhance documentation to clearly warn developers about the critical risks associated with allowing untrusted input to influence
COMPRESS_PRECOMPILERSand other precompiler-related settings. Emphasize secure configuration management and access control to Django settings.
- Input Sanitization: Implement comprehensive input sanitization for all parts of the command strings and any options used in
-
Preconditions:
- Attacker Influence on Settings: The attacker must be able to influence Django project settings, specifically the
COMPRESS_PRECOMPILERSsetting. This could be achieved through a separate vulnerability, a misconfiguration that exposes settings, or if file names or configuration values are allowed to be influenced by untrusted input (e.g., via file upload or static asset naming). - Precompilers Enabled: The Django application must be configured to use precompilers defined in
COMPRESS_PRECOMPILERS. - Trigger Compression: An attacker needs to trigger the compression process for content that will utilize the precompiler with the injected command. This typically involves rendering a Django template that includes a
{% compress %}block containing a file type associated with the malicious precompiler configuration.
- Attacker Influence on Settings: The attacker must be able to influence Django project settings, specifically the
-
Source Code Analysis:
-
Configuration: File:
/code/compressor/conf.pyclass CompressorConf(AppConf): # ... PRECOMPILERS = ( # ('text/coffeescript', 'coffee --compile --stdio'), # ('text/less', 'lessc {infile} {outfile}'), # ... ) # ...
COMPRESS_PRECOMPILERSsetting defines tuples of mimetype and command templates. These templates are intended for developer configuration but can be vulnerable if modifiable by attackers.
-
Command Execution: File:
/code/compressor/filters/base.pyclass CompilerFilter(FilterBase): command = None options = () # ... def input(self, **kwargs): # ... try: command = self.command.format(**options) proc = subprocess.Popen( command, shell=True, # <--- Vulnerable: shell=True cwd=self.cwd, stdout=self.stdout, stdin=self.stdin, stderr=self.stderr, ) # ... except (IOError, OSError) as e: raise FilterError( "Unable to apply %s (%r): %s" % (self.__class__.__name__, self.command, e) ) # ...
- The
CompilerFilter.inputmethod formats theself.commandstring usingself.command.format(**options). - It then executes the formatted command using
subprocess.Popen(command, shell=True, ...). - Vulnerability: The use of
shell=Trueinsubprocess.Popenis the core vulnerability. It allows shell metacharacters and command chaining to be interpreted by the shell, if the command string oroptionsare attacker-controlled or not properly sanitized. - Visualization of Command Construction:
- Template:
"%(binary)s %(args)s {infile} {outfile}"(Example template fromCOMPRESS_PRECOMPILERS) - Parameter Preparation:
{infile}and{outfile}are sanitized using shell quoting (on non-Windows).- Other parameters (e.g.,
{binary},{args}, or custom placeholders) are taken directly from configuration without sanitization.
- Formatting: Unsanitized placeholders are substituted into the command template. If an attacker controls these values, the final command could become:
"trusted_binary --safe_arg " + malicious_payload. - Execution: The constructed command is executed with
shell=True, leading to the execution of injected shell commands.
- Template:
- The
-
-
Security Test Case:
-
Setup:
- Configure a Django project with django-compressor.
- Modify
settings.pyto include a malicious precompiler inCOMPRESS_PRECOMPILERS:COMPRESS_PRECOMPILERS = [ ('text/x-pwned', 'touch /tmp/django_compressor_pwned_{cachekey}; {infile} {outfile}') ]
- Ensure
COMPRESS_ENABLED = Trueand 'compressor' is inINSTALLED_APPS. - Create a Django template that triggers the precompiler:
{% load compress %} {% compress css %} <style type="text/x-pwned">body { color: red; }</style> {% endcompress %} - Create a Django view to render this template and map it to a URL.
-
Execution:
- Access the URL in a web browser or using
curlthat renders the template. This action triggers thecompresstemplate tag and the processing of the<style type="text/x-pwned">block.
- Access the URL in a web browser or using
-
Verification:
- Check for the existence of the file
/tmp/django_compressor_pwned_<cachekey>on the server. Replace<cachekey>with an expected cache key value or check for any file starting with/tmp/django_compressor_pwned_. - Successful creation of this file confirms that the
touchcommand injected viaCOMPRESS_PRECOMPILERSwas executed, demonstrating command injection.
- Check for the existence of the file
-
-
Vulnerability Name: Path Traversal Vulnerability in CSS URL Rewriting
-
Description:
- The
CssAbsoluteFilterandCssRelativeFilterclasses in/code/compressor/filters/css_default.pyrewrite URLs within CSS files to be absolute or relative. - The
guess_filenamemethod withinCssAbsoluteFilterconstructs a file path by joiningsettings.COMPRESS_ROOTwith alocal_pathderived from URLs in the CSS. - This
local_pathis not properly sanitized against path traversal attacks. An attacker can craft a CSS file with URLs containing directory traversal sequences (e.g.,../). - When
CssAbsoluteFilterorCssRelativeFilterprocesses this CSS,guess_filenameis called for each URL. Due to insufficient sanitization, traversal sequences in the URL are preserved inlocal_path. os.path.join(self.root, local_path.lstrip("/"))constructs a file path potentially outside ofCOMPRESS_ROOT.- The vulnerability manifests during file existence checks (
os.path.exists) and hash generation (get_hashed_mtime,get_hashed_content) within the filters, potentially leading to information disclosure if error messages reveal file system structure or file existence outsideCOMPRESS_ROOT.
- The
-
Impact:
- Path Traversal: Attackers can construct paths that reach outside of the intended
COMPRESS_ROOTdirectory. - Information Disclosure (Potential): While direct file reading is not immediately evident, the vulnerability can lead to information disclosure if error messages or logs reveal information about the file system structure or the existence of files outside of
COMPRESS_ROOT. In combination with other vulnerabilities or misconfigurations, this could be chained to more severe exploits.
- Path Traversal: Attackers can construct paths that reach outside of the intended
-
Vulnerability Rank: High
-
Currently Implemented Mitigations:
- None. The
guess_filenamemethod inCssAbsoluteFilterand related methods do not sanitize or validate thelocal_pathto prevent directory traversal.
- None. The
-
Missing Mitigations:
- Input Sanitization: Implement robust input sanitization for URLs within
CssAbsoluteFilterandCssRelativeFilter, specifically within theguess_filenamemethod and potentially in the_convertermethod.- Validate
local_pathto ensure it does not contain directory traversal sequences like../. - Use secure path manipulation functions that prevent traversal or explicitly resolve and check if the resulting path stays within
COMPRESS_ROOT.
- Validate
- Input Sanitization: Implement robust input sanitization for URLs within
-
Preconditions:
COMPRESS_ENABLEDis True.CssAbsoluteFilterorCssRelativeFilteris enabled inCOMPRESS_FILTERS['css'](default configuration).- The application uses
{% compress css %}to process CSS content that may contain crafted URLs.
-
Source Code Analysis:
File: /code/compressor/filters/css_default.py def guess_filename(self, url): local_path = url if self.has_scheme: # ... (URL cleaning) ... # Re-build the local full path by adding root filename = os.path.join(self.root, local_path.lstrip("/")) # Vulnerable line return os.path.exists(filename) and filename
guess_filenameprocesses URLs from CSS content.os.path.join(self.root, local_path.lstrip("/"))joinsCOMPRESS_ROOT(self.root) withlocal_path.local_path.lstrip("/")only removes leading slashes, not preventing directory traversal sequences withinlocal_path.- Crafted URLs with
../sequences in CSS will result infilenamepointing to locations outsideCOMPRESS_ROOT. os.path.exists(filename)and hash generation functions will then operate on these potentially out-of-bounds paths.
-
Security Test Case:
-
Preconditions:
- Django project with
django-compressorenabled. - Default CSS filters active.
- Publicly accessible view rendering a template with
{% compress css %}. - A sensitive file
sensitive.txtoutsideCOMPRESS_ROOTbut accessible to the Django application.
- Django project with
-
Test Steps:
- Create
malicious.cssin static files:.malicious-class { background-image: url('../../../../sensitive.txt'); /* Traversal to project root */ }
- Create/modify a Django template:
{% load static compress %} {% compress css %} <link rel="stylesheet" href="{% static 'malicious.css' %}" type="text/css"> {% endcompress %}
- Access the view rendering the template.
- Examine the rendered HTML source code and server logs.
- Create
-
Expected Result (Vulnerable):
- Template renders without critical errors.
- Server logs may show attempts to access paths outside
COMPRESS_ROOT. - While direct content disclosure might not be immediately visible, the unsafe path construction and potential for information leakage via logs or error conditions confirm the path traversal vulnerability. If hashing is involved, attempts to hash
sensitive.txtwould confirm path traversal.
-
Note: This test demonstrates path traversal in path construction. Direct file content disclosure might require further exploitation or configuration adjustments. The key is to confirm that directory traversal sequences are not handled, leading to path construction outside of COMPRESS_ROOT.