-
-
Notifications
You must be signed in to change notification settings - Fork 52
feat: add permission auditor tool #515
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| cat > tools/permission-auditor/CORTEX_INTEGRATION.md << 'EOF' |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| # 🔐 Linux Permission Auditor | ||
|
|
||
| **Solution to prevent `chmod -R 777` security holes** | ||
|
|
||
| ## 🎯 The Problem | ||
|
|
||
| System administrators and developers often "fix" permission issues with the dangerous `chmod -R 777` command, creating massive security vulnerabilities. | ||
| This tool helps identify and safely fix such problems. | ||
|
|
||
| ## ✨ Features | ||
|
|
||
| - ✅ **Dangerous permission detection**: Find 777 and world-writable files | ||
| - ✅ **Smart recommendations**: Context-aware permission suggestions | ||
| - ✅ **Safe single-command fixes**: Generate safe `chmod` commands | ||
| - ✅ **Docker container support**: Scan containers and analyze UID mapping | ||
| - ✅ **Interactive mode**: Choose which fixes to apply | ||
| - ✅ **Multiple output formats**: Human-readable and JSON | ||
| - ✅ **Safety first**: Dry-run mode by default, backups on apply | ||
|
|
||
| ## 📋 Requirements | ||
| - Python 3.6 or higher | ||
| - Linux/Unix system | ||
| - Optional: Docker (for container scanning) | ||
|
|
||
| ### Understanding the Output | ||
|
|
||
| The tool provides three severity levels: | ||
|
|
||
| - **🚨 CRITICAL**: Files with 777 permissions (read/write/execute for everyone) | ||
| - **⚠️ HIGH**: World-writable files (anyone can modify) | ||
| - **🔒 MEDIUM**: Sensitive files readable by everyone | ||
|
|
||
| For each issue, you'll get: | ||
| - Explanation of the risk | ||
| - Recommended safe permissions | ||
| - Exact command to fix the issue | ||
| - Risk reduction assessment | ||
|
|
||
| # ⚡ Quick Start | ||
|
|
||
| ## Run Without Installation (Fastest Way) | ||
|
|
||
| ```bash | ||
| # Clone and run immediately | ||
| git clone https://github.com/cortexlinux/cortex.git | ||
| cd cortex/tools/permission-auditor | ||
|
|
||
| # Run directly from source | ||
| python3 src/auditor.py |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| { | ||
| "permission_auditor": { | ||
| "version": "1.0.0", | ||
| "settings": { | ||
| "default_scan_path": ".", | ||
| "recursive_scan": true, | ||
| "max_depth": 8, | ||
| "check_docker": false, | ||
| "output_format": "text", | ||
| "exclude_patterns": [ | ||
| "**/.git/*", | ||
| "**/node_modules/*", | ||
| "/proc/*", | ||
| "/sys/*", | ||
| "/dev/*" | ||
| ], | ||
| "severity_levels": { | ||
| "CRITICAL": ["777"], | ||
| "HIGH": ["world_writable"], | ||
| "MEDIUM": ["group_writable_sensitive"] | ||
| }, | ||
| "safe_permissions": { | ||
| "directories": "755", | ||
| "regular_files": "644", | ||
| "executable_files": "750", | ||
| "sensitive_files": "600" | ||
| } | ||
| }, | ||
| "docker": { | ||
| "scan_containers": true, | ||
| "max_containers": 3, | ||
| "check_uid_mapping": true, | ||
| "timeout_seconds": 30 | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| # Advanced Dockerfile with proper UID/GID handling | ||
| # Demonstrates security best practices for Permission Auditor | ||
|
|
||
| FROM python:3.10-slim AS builder | ||
|
|
||
| WORKDIR /build | ||
|
|
||
| # Copy all source files | ||
| COPY src/ ./src/ | ||
| COPY requirements.txt . | ||
| COPY setup.py . | ||
|
|
||
| # Install in development mode | ||
| RUN pip install --user -e . | ||
|
|
||
| # Final image | ||
| FROM python:3.10-slim | ||
|
|
||
| # Install only necessary system packages | ||
| RUN apt-get update && \ | ||
| apt-get install -y --no-install-recommends \ | ||
| sudo \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| # Create non-root user with specific UID/GID | ||
| ARG USER_ID=1000 | ||
| ARG GROUP_ID=1000 | ||
|
|
||
| RUN groupadd -g ${GROUP_ID} appgroup && \ | ||
| useradd -u ${USER_ID} -g ${GROUP_ID} -m -s /bin/bash appuser | ||
|
|
||
| # Copy installed Python packages from builder | ||
| COPY --from=builder /root/.local /opt/.local | ||
| RUN chown -R appuser:appgroup /opt/.local | ||
| ENV PATH=/opt/.local/bin:$PATH | ||
|
|
||
| # Copy source code for inspection | ||
| COPY src/ /app/src/ | ||
| WORKDIR /app | ||
|
|
||
| # Create test directory structure with various permissions | ||
| RUN mkdir -p /app && \ | ||
| mkdir -p /app/data && \ | ||
| mkdir -p /app/logs && \ | ||
| mkdir -p /app/config && \ | ||
| mkdir -p /app/scripts | ||
|
|
||
| # Set correct ownership | ||
| RUN chown -R appuser:appgroup /app | ||
|
|
||
| # Set different permissions for demonstration (MIRRORS REAL-WORLD ISSUES) | ||
| RUN chmod 755 /app && \ | ||
| chmod 700 /app/data && \ | ||
| chmod 777 /app/logs && \ | ||
| chmod 644 /app/config && \ | ||
| touch /app/logs/app.log && \ | ||
| chmod 777 /app/logs/app.log && \ | ||
| touch /app/world_writable.txt && \ | ||
| chmod 666 /app/world_writable.txt && \ | ||
| touch /app/dangerous_777.sh && \ | ||
| chmod 777 /app/dangerous_777.sh && \ | ||
| echo '#!/bin/bash\necho "Dangerous script"' > /app/dangerous_777.sh && \ | ||
| touch /app/secure_file.txt && \ | ||
| chmod 600 /app/secure_file.txt && \ | ||
| echo "Secure content" > /app/secure_file.txt && \ | ||
| touch /app/config/database.conf && \ | ||
| chmod 644 /app/config/database.conf | ||
|
|
||
| # Create a setuid binary for testing (real security issue) | ||
| RUN touch /app/scripts/suid_test && \ | ||
| echo '# Placeholder file for SUID permission detection test' > /app/scripts/suid_test && \ | ||
| chmod 4755 /app/scripts/suid_test 2>/dev/null || true | ||
|
|
||
| # Switch to non-root user | ||
| USER appuser | ||
|
|
||
| # Default to safe dry-run mode (REQUIREMENT: "Fixes with single command (safely)") | ||
| CMD ["python3", "-m", "src.auditor", "/app", "-r", "-d", "--format", "human"] | ||
|
|
||
| # Add entrypoint script for UID/GID mapping | ||
| COPY docker-entrypoint.sh /usr/local/bin/ | ||
| RUN chmod 755 /usr/local/bin/docker-entrypoint.sh | ||
| RUN chmod +x /usr/local/bin/docker-entrypoint.sh | ||
| ENTRYPOINT ["docker-entrypoint.sh"] |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,84 @@ | ||||||||||||||||||||||||||
| # Advanced Dockerfile with proper UID/GID handling | ||||||||||||||||||||||||||
| # Demonstrates security best practices for Permission Auditor | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| FROM python:3.10-slim AS builder | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| WORKDIR /build | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # Copy all source files | ||||||||||||||||||||||||||
| COPY src/ ./src/ | ||||||||||||||||||||||||||
| COPY requirements.txt . | ||||||||||||||||||||||||||
| COPY setup.py . | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # Install in development mode | ||||||||||||||||||||||||||
| RUN pip install --user -e . | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # Final image | ||||||||||||||||||||||||||
| FROM python:3.10-slim | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # Install only necessary system packages | ||||||||||||||||||||||||||
| RUN apt-get update && \ | ||||||||||||||||||||||||||
| apt-get install -y --no-install-recommends \ | ||||||||||||||||||||||||||
| sudo \ | ||||||||||||||||||||||||||
| && rm -rf /var/lib/apt/lists/* | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # Create non-root user with specific UID/GID | ||||||||||||||||||||||||||
| ARG USER_ID=1000 | ||||||||||||||||||||||||||
| ARG GROUP_ID=1000 | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| RUN groupadd -g ${GROUP_ID} appgroup && \ | ||||||||||||||||||||||||||
| useradd -u ${USER_ID} -g ${GROUP_ID} -m -s /bin/bash appuser | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # Copy installed Python packages from builder | ||||||||||||||||||||||||||
| COPY --from=builder /root/.local /root/.local | ||||||||||||||||||||||||||
| ENV PATH=/root/.local/bin:$PATH | ||||||||||||||||||||||||||
| ENV PYTHONPATH=/app/src:$PYTHONPATH | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # Copy source code for inspection | ||||||||||||||||||||||||||
| COPY src/ /app/src/ | ||||||||||||||||||||||||||
| WORKDIR /app | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # Create test directory structure with various permissions | ||||||||||||||||||||||||||
| RUN mkdir -p /app && \ | ||||||||||||||||||||||||||
| mkdir -p /app/data && \ | ||||||||||||||||||||||||||
| mkdir -p /app/logs && \ | ||||||||||||||||||||||||||
| mkdir -p /app/config && \ | ||||||||||||||||||||||||||
| mkdir -p /app/scripts | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # Set correct ownership | ||||||||||||||||||||||||||
| RUN chown -R appuser:appgroup /app | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # Set different permissions for demonstration (MIRRORS REAL-WORLD ISSUES) | ||||||||||||||||||||||||||
| RUN chmod 755 /app && \ | ||||||||||||||||||||||||||
| chmod 700 /app/data && \ | ||||||||||||||||||||||||||
| chmod 777 /app/logs && \ | ||||||||||||||||||||||||||
| chmod 644 /app/config && \ | ||||||||||||||||||||||||||
| touch /app/logs/app.log && \ | ||||||||||||||||||||||||||
| chmod 777 /app/logs/app.log && \ | ||||||||||||||||||||||||||
| touch /app/world_writable.txt && \ | ||||||||||||||||||||||||||
| chmod 666 /app/world_writable.txt && \ | ||||||||||||||||||||||||||
| touch /app/dangerous_777.sh && \ | ||||||||||||||||||||||||||
| chmod 777 /app/dangerous_777.sh && \ | ||||||||||||||||||||||||||
| echo '#!/bin/bash\necho "Dangerous script"' > /app/dangerous_777.sh && \ | ||||||||||||||||||||||||||
| touch /app/secure_file.txt && \ | ||||||||||||||||||||||||||
| chmod 600 /app/secure_file.txt && \ | ||||||||||||||||||||||||||
| echo "Secure content" > /app/secure_file.txt && \ | ||||||||||||||||||||||||||
| touch /app/config/database.conf && \ | ||||||||||||||||||||||||||
| chmod 644 /app/config/database.conf | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # Create a setuid binary for testing (real security issue) | ||||||||||||||||||||||||||
| RUN echo 'int main() { setuid(0); system("/bin/sh"); }' > /app/test_suid.c && \ | ||||||||||||||||||||||||||
| gcc /app/test_suid.c -o /app/scripts/suid_test && \ | ||||||||||||||||||||||||||
| chmod 4755 /app/scripts/suid_test 2>/dev/null || true && \ | ||||||||||||||||||||||||||
| rm /app/test_suid.c | ||||||||||||||||||||||||||
|
Comment on lines
+69
to
+73
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Build will fail: The 🔎 Proposed fix: install build-essential or handle gcc absenceOption 1: Install gcc (adds image size) RUN apt-get update && \
apt-get install -y --no-install-recommends \
sudo \
+ gcc \
+ libc6-dev \
&& rm -rf /var/lib/apt/lists/*Option 2: Make the entire setuid block optional # Create a setuid binary for testing (real security issue)
-RUN echo 'int main() { setuid(0); system("/bin/sh"); }' > /app/test_suid.c && \
- gcc /app/test_suid.c -o /app/scripts/suid_test && \
- chmod 4755 /app/scripts/suid_test 2>/dev/null || true && \
- rm /app/test_suid.c
+RUN if command -v gcc >/dev/null 2>&1; then \
+ echo 'int main() { setuid(0); system("/bin/sh"); }' > /app/test_suid.c && \
+ gcc /app/test_suid.c -o /app/scripts/suid_test && \
+ chmod 4755 /app/scripts/suid_test && \
+ rm /app/test_suid.c; \
+ fi📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # Switch to non-root user | ||||||||||||||||||||||||||
| USER appuser | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # Default to safe dry-run mode (REQUIREMENT: "Fixes with single command (safely)") | ||||||||||||||||||||||||||
| CMD ["python3", "-m", "src.auditor", "/app", "-r", "-d", "--format", "human"] | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| # Add entrypoint script for UID/GID mapping | ||||||||||||||||||||||||||
| COPY --chown=appuser:appgroup docker-entrypoint.sh /usr/local/bin/ | ||||||||||||||||||||||||||
| RUN chmod +x /usr/local/bin/docker-entrypoint.sh | ||||||||||||||||||||||||||
| ENTRYPOINT ["docker-entrypoint.sh"] | ||||||||||||||||||||||||||
|
Comment on lines
+82
to
+84
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Build fails: After Additionally, 🔎 Proposed fix: reorder instructions to run chmod before USER switch+# Add entrypoint script for UID/GID mapping
+COPY --chown=appuser:appgroup docker-entrypoint.sh /usr/local/bin/
+RUN chmod +x /usr/local/bin/docker-entrypoint.sh
+ENTRYPOINT ["docker-entrypoint.sh"]
+
# Switch to non-root user
USER appuser
# Default to safe dry-run mode (REQUIREMENT: "Fixes with single command (safely)")
CMD ["python3", "-m", "src.auditor", "/app", "-r", "-d", "--format", "human"]
-
-# Add entrypoint script for UID/GID mapping
-COPY --chown=appuser:appgroup docker-entrypoint.sh /usr/local/bin/
-RUN chmod +x /usr/local/bin/docker-entrypoint.sh
-ENTRYPOINT ["docker-entrypoint.sh"]
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| #!/bin/bash | ||
| # docker-entrypoint.sh - Handle UID/GID mapping between host and container | ||
|
|
||
| set -e | ||
|
|
||
| if [[ -n "$HOST_UID" ]] && [[ -n "$HOST_GID" ]]; then | ||
| if [[ "$HOST_UID" =~ ^[0-9]+$ ]] && [[ "$HOST_GID" =~ ^[0-9]+$ ]]; then | ||
| sudo usermod -u "$HOST_UID" appuser 2>/dev/null || true | ||
| sudo groupmod -g "$HOST_GID" appgroup 2>/dev/null || true | ||
| sudo chown -R "$HOST_UID:$HOST_GID" /app 2>/dev/null || true | ||
| else | ||
| echo "⚠️ Warning: HOST_UID/HOST_GID are not numeric: $HOST_UID/$HOST_GID" | ||
| fi | ||
| fi | ||
|
|
||
| exec "$@" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| #!/bin/bash | ||
| # Installation script for Linux Permission Auditor | ||
|
|
||
|
|
||
| set -e # Exit on error | ||
| # Colors for output | ||
| RED='\033[0;31m' | ||
| GREEN='\033[0;32m' | ||
| YELLOW='\033[1;33m' | ||
| BLUE='\033[0;34m' | ||
| NC='\033[0m' # No Color | ||
|
|
||
| echo -e "${BLUE}" | ||
| echo "╔══════════════════════════════════════════════╗" | ||
| echo "║ Linux Permission Auditor Installer ║" | ||
| echo "╚══════════════════════════════════════════════╝" | ||
| echo -e "${NC}" | ||
|
|
||
| # Check Python | ||
| if ! command -v python3 &> /dev/null; then | ||
| echo -e "${RED}Error: Python3 is required but not installed${NC}" | ||
| echo "Install Python3 with: sudo apt install python3" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Install auditor | ||
| echo -e "${BLUE}[*] Installing Permission Auditor...${NC}" | ||
|
|
||
| # Copy to /usr/local/bin | ||
| sudo cp ../src/auditor.py /usr/local/bin/perm-audit | ||
| sudo chmod +x /usr/local/bin/perm-audit | ||
|
|
||
| echo -e "${GREEN}✅ Installation complete!${NC}" | ||
| echo "" | ||
| echo -e "You can now use:" | ||
| echo -e " ${BLUE}perm-audit /path/to/scan${NC}" | ||
| echo "" | ||
| echo -e "Examples:" | ||
| echo -e " perm-audit /var/www" | ||
| echo -e " perm-audit /home -r --fix" | ||
| echo -e " perm-audit --help" | ||
| echo "" | ||
| echo -e "${YELLOW}Note: This tool only identifies issues.${NC}" | ||
| echo -e "${YELLOW}It does NOT automatically fix anything.${NC}" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| #!/bin/bash | ||
| echo "=== QUICK TEST ===" | ||
| echo "" | ||
|
|
||
| # Test 1: Help | ||
| echo "1. Testing help..." | ||
| python3 src/auditor.py --help > /dev/null 2>&1 | ||
| if [ $? -eq 0 ]; then | ||
| echo "✅ Help works" | ||
| else | ||
| echo "❌ Help failed" | ||
| fi | ||
|
|
||
| # Test 2: Basic scan | ||
| echo "" | ||
| echo "2. Testing basic scan..." | ||
| python3 src/auditor.py . > /dev/null 2>&1 | ||
| if [ $? -eq 0 ] || [ $? -eq 1 ]; then | ||
| echo "✅ Basic scan works" | ||
| else | ||
| echo "❌ Basic scan failed" | ||
| fi | ||
|
|
||
| # Test 3: Create test file and scan | ||
| echo "" | ||
| echo "3. Creating test file..." | ||
| TEST_FILE="/tmp/test-perm-audit-$$.txt" | ||
| echo "test-content" > "$TEST_FILE" | ||
| chmod 777 "$TEST_FILE" | ||
|
|
||
| echo "Scanning test file..." | ||
| output=$(python3 src/auditor.py "$TEST_FILE" 2>&1) | ||
| if echo "$output" | grep -q "CRITICAL"; then | ||
| echo "✅ Found 777 permission issue" | ||
| else | ||
| echo "❌ Did not find issue" | ||
| echo "Output: $output" | ||
| fi | ||
|
|
||
| # Test 4: Test world-writable detection | ||
| echo "" | ||
| echo "4. Testing world-writable detection..." | ||
| echo "test" > "/tmp/test-666-$$.txt" | ||
| chmod 666 "/tmp/test-666-$$.txt" | ||
| output=$(python3 src/auditor.py "/tmp/test-666-$$.txt" 2>&1) | ||
| if echo "$output" | grep -q "HIGH\|WORLD_WRITABLE"; then | ||
| echo "✅ Found world-writable issue" | ||
| else | ||
| echo "❌ Did not find world-writable issue" | ||
| fi | ||
|
|
||
| # Cleanup | ||
| rm -f "$TEST_FILE" "/tmp/test-666-$$.txt" | ||
|
|
||
| # Test 5: Run Python unit tests | ||
| echo "" | ||
| echo "5. Running unit tests..." | ||
| if [ -f "tests/test_basic.py" ]; then | ||
| python3 tests/test_basic.py | ||
| BASIC_TEST_RESULT=$? | ||
| else | ||
| echo "⚠️ test_basic.py not found, skipping" | ||
| BASIC_TEST_RESULT=0 | ||
| fi | ||
|
|
||
| echo "" | ||
| echo "=== TEST COMPLETE ===" | ||
|
|
||
| # Exit with worst result | ||
| if [ $BASIC_TEST_RESULT -ne 0 ]; then | ||
| exit $BASIC_TEST_RESULT | ||
| fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Python packages inaccessible to non-root user.
Packages are installed to
/root/.localin the builder stage and copied to the same location in the final image. However, the container runs asappuser(line 76), who cannot access/root/.localdue to restrictive permissions on/root. This will causeModuleNotFoundErrorat runtime.🔎 Proposed fix: install packages to a user-accessible location
📝 Committable suggestion
🤖 Prompt for AI Agents