VYPR
High severity8.8NVD Advisory· Published May 8, 2026· Updated May 8, 2026

CVE-2026-41900

CVE-2026-41900

Description

OpenLearnX is an open-source, decentralized learning and assessment platform. Prior to version 2.0.3, a remote code execution (RCE) vulnerability was identified in the OpenLearnX code execution environment, allowing sandbox escape and arbitrary command execution. This issue has been patched in version 2.0.3.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
openlearnxnpm
< 2.0.32.0.3

Patches

1
14765d7d1856

fix(security): harden execution sandbox and add dedicated admin execution logs

https://github.com/th30d4y/OpenLearnXStalinApr 19, 2026via ghsa
12 files changed · +1282 820
  • backend/routes/admin.py+94 0 modified
    @@ -371,6 +371,100 @@ def get_admin_logs():
             return jsonify({"error": str(e)}), 500
     
     
    +@bp.route("/logs/executions", methods=["GET"])
    +@admin_required
    +def get_execution_logs():
    +    """Query compiler/coding execution events as a dedicated log stream."""
    +    try:
    +        language = request.args.get("language", "").strip().lower()
    +        status = request.args.get("status", "").strip().lower()
    +        search = request.args.get("search", "").strip()
    +        from_ts = request.args.get("from", "").strip()
    +        to_ts = request.args.get("to", "").strip()
    +        limit = min(max(int(request.args.get("limit", 100)), 1), 500)
    +        page = max(int(request.args.get("page", 1)), 1)
    +
    +        query = {}
    +        if language:
    +            query["language"] = language
    +        if status:
    +            query["status"] = status
    +
    +        ts_filter = {}
    +        if from_ts:
    +            try:
    +                ts_filter["$gte"] = datetime.fromisoformat(from_ts)
    +            except Exception:
    +                pass
    +        if to_ts:
    +            try:
    +                ts_filter["$lte"] = datetime.fromisoformat(to_ts)
    +            except Exception:
    +                pass
    +        if ts_filter:
    +            query["timestamp"] = ts_filter
    +
    +        if search:
    +            safe = re.escape(search)
    +            query["$or"] = [
    +                {"execution_id": {"$regex": safe, "$options": "i"}},
    +                {"language": {"$regex": safe, "$options": "i"}},
    +                {"source": {"$regex": safe, "$options": "i"}},
    +                {"ip": {"$regex": safe, "$options": "i"}},
    +                {"status": {"$regex": safe, "$options": "i"}},
    +                {"error": {"$regex": safe, "$options": "i"}},
    +            ]
    +
    +        skip = (page - 1) * limit
    +        total = db.code_execution_events.count_documents(query)
    +        docs = list(db.code_execution_events.find(query).sort("timestamp", -1).skip(skip).limit(limit))
    +
    +        logs = []
    +        for doc in docs:
    +            item = _json_safe(doc)
    +            item["id"] = str(item.get("_id"))
    +            item.pop("_id", None)
    +
    +            if not item.get("source"):
    +                item["source"] = "compiler"
    +
    +            if not item.get("request_body"):
    +                item["request_body"] = {
    +                    "language": item.get("language", "unknown"),
    +                    "code": "Legacy log entry (request code body was not captured at execution time)",
    +                    "code_size": item.get("code_size", 0),
    +                }
    +
    +            if not item.get("response_body"):
    +                item["response_body"] = {
    +                    "success": item.get("status") == "success",
    +                    "blocked": bool(item.get("blocked")),
    +                    "execution_id": item.get("execution_id"),
    +                    "error": item.get("error", ""),
    +                    "security_violations": item.get("security_violations", []),
    +                    "execution_time": item.get("execution_time", 0),
    +                    "memory_used": item.get("memory_used", 0),
    +                    "exit_code": item.get("exit_code", 0),
    +                    "note": "Legacy log entry (response payload was not captured at execution time)",
    +                }
    +
    +            logs.append(item)
    +
    +        return jsonify({
    +            "success": True,
    +            "logs": logs,
    +            "pagination": {
    +                "page": page,
    +                "limit": limit,
    +                "total": total,
    +                "pages": (total + limit - 1) // limit,
    +            },
    +        })
    +    except Exception as e:
    +        print(f"Error getting execution logs: {str(e)}")
    +        return jsonify({"error": str(e)}), 500
    +
    +
     @bp.route("/users", methods=["GET"])
     @admin_required
     def get_admin_users():
    
  • backend/routes/coding.py+92 63 modified
    @@ -10,6 +10,7 @@
     import psutil
     from pymongo import MongoClient
     from activity_logger import log_user_activity, resolve_user_identity
    +from services.real_compiler_service import real_compiler_service
     
     bp = Blueprint('coding', __name__)
     
    @@ -86,10 +87,81 @@ def execute_code():
             # Log coding attempt
             log_coding_attempt(session['coding_session_id'], code, language)
             
    -        # Execute code in secure container
    -        result = execute_in_container(code, language, test_cases)
    -        
    -        return jsonify(result)
    +        # Execute code in hardened Docker sandbox
    +        result = real_compiler_service.execute_code(code=code, language=language, input_data="")
    +
    +        event_type = "coding_execution_success" if result.get("success") else "coding_execution_blocked"
    +        severity = "info" if result.get("success") else "warning"
    +
    +        execution_status = "success" if result.get("success") else "failed"
    +        if result.get("blocked"):
    +            execution_status = "blocked"
    +
    +        db.security_logs.insert_one({
    +            "timestamp": datetime.utcnow(),
    +            "event_type": event_type,
    +            "action": "secure_coding_execute",
    +            "status_code": 200 if result.get("success") else 400,
    +            "severity": severity,
    +            "path": request.path,
    +            "method": request.method,
    +            "ip": request.remote_addr or "unknown",
    +            "user_agent": request.headers.get("User-Agent", ""),
    +            "metadata": {
    +                "language": language,
    +                "execution_id": result.get("execution_id"),
    +                "blocked": bool(result.get("blocked")),
    +                "security_violations": result.get("security_violations", []),
    +                "execution_time": result.get("execution_time", 0),
    +                "memory_used": result.get("memory_used", 0),
    +                "exit_code": result.get("exit_code", -1),
    +            },
    +            "metadata_text": str(result.get("security_violations", [])),
    +        })
    +
    +        try:
    +            request_payload = {
    +                "language": language,
    +                "code": (code or "")[:4000],
    +                "code_size": len(code or ""),
    +                "test_case_count": len(test_cases) if isinstance(test_cases, list) else 0,
    +            }
    +            response_payload = {
    +                "success": bool(result.get("success")),
    +                "blocked": bool(result.get("blocked")),
    +                "execution_id": result.get("execution_id"),
    +                "output": (result.get("output") or "")[:4000],
    +                "error": result.get("error", ""),
    +                "security_violations": result.get("security_violations", []),
    +                "execution_time": result.get("execution_time", 0),
    +                "memory_used": result.get("memory_used", 0),
    +                "exit_code": result.get("exit_code", -1),
    +            }
    +
    +            db.code_execution_events.insert_one({
    +                "timestamp": datetime.utcnow(),
    +                "event_type": "execution",
    +                "source": "coding",
    +                "language": language,
    +                "execution_id": result.get("execution_id"),
    +                "execution_time": result.get("execution_time", 0),
    +                "memory_used": result.get("memory_used", 0),
    +                "exit_code": result.get("exit_code", -1),
    +                "status": execution_status,
    +                "blocked": bool(result.get("blocked")),
    +                "security_violations": result.get("security_violations", []),
    +                "error": result.get("error", ""),
    +                "request_body": request_payload,
    +                "response_body": response_payload,
    +                "ip": request.remote_addr or "unknown",
    +                "user_agent": request.headers.get("User-Agent", ""),
    +            })
    +        except Exception:
    +            pass
    +
    +        if result.get("success"):
    +            return jsonify({"success": True, **result})
    +        return jsonify({"success": False, **result}), 400
         except Exception as e:
             return jsonify({"error": str(e)}), 500
     
    @@ -156,66 +228,23 @@ def submit_coding_test():
             return jsonify({"error": str(e)}), 500
     
     def execute_in_container(code, language, test_cases):
    -    """Execute code in secure Docker container"""
    -    try:
    -        client = docker.from_env()
    -        
    -        # Language-specific container configuration
    -        containers = {
    -            'python': 'python:3.9-alpine',
    -            'java': 'openjdk:11-alpine',
    -            'javascript': 'node:16-alpine'
    +    """Backward-compatible wrapper around the hardened compiler service."""
    +    result = real_compiler_service.execute_code(code=code, language=language, input_data="")
    +    if result.get("success"):
    +        return {
    +            "success": True,
    +            "output": result.get("output", ""),
    +            "test_results": [],
    +            "execution_time": result.get("execution_time", 0),
    +            "memory_used": result.get("memory_used", 0),
    +            "execution_id": result.get("execution_id"),
             }
    -        
    -        if language not in containers:
    -            return {"error": "Unsupported language"}
    -        
    -        # Create temporary file
    -        with tempfile.NamedTemporaryFile(mode='w', suffix=f'.{get_file_extension(language)}', delete=False) as f:
    -            f.write(code)
    -            temp_file = f.name
    -        
    -        try:
    -            # Run container with security restrictions
    -            container = client.containers.run(
    -                containers[language],
    -                command=get_run_command(language, temp_file),
    -                volumes={os.path.dirname(temp_file): {'bind': '/app', 'mode': 'ro'}},
    -                working_dir='/app',
    -                mem_limit='128m',
    -                cpu_period=100000,
    -                cpu_quota=50000,  # 50% CPU limit
    -                network_mode='none',  # No network access
    -                remove=True,
    -                timeout=10,  # 10 second timeout
    -                detach=False
    -            )
    -            
    -            output = container.decode('utf-8')
    -            
    -            # Run test cases if provided
    -            test_results = []
    -            if test_cases:
    -                for test in test_cases:
    -                    test_result = run_test_case(code, language, test)
    -                    test_results.append(test_result)
    -            
    -            return {
    -                "success": True,
    -                "output": output,
    -                "test_results": test_results,
    -                "execution_time": "< 10s"
    -            }
    -            
    -        finally:
    -            os.unlink(temp_file)
    -            
    -    except docker.errors.ContainerError as e:
    -        return {"error": f"Runtime error: {e}"}
    -    except docker.errors.ImageNotFound:
    -        return {"error": "Language runtime not available"}
    -    except Exception as e:
    -        return {"error": f"Execution failed: {str(e)}"}
    +    return {
    +        "success": False,
    +        "error": result.get("error", "Execution failed"),
    +        "security_violations": result.get("security_violations", []),
    +        "execution_id": result.get("execution_id"),
    +    }
     
     def get_file_extension(language):
         extensions = {
    
  • backend/routes/compiler.py+201 521 modified
    @@ -1,546 +1,226 @@
    -from flask import Blueprint, request, jsonify
    -import subprocess
    -import tempfile
    -import os
    -import time
    -import docker
     from datetime import datetime
    +import os
     
    -bp = Blueprint('compiler', __name__)
    +from flask import Blueprint, jsonify, request
    +from pymongo import MongoClient
     
    -def get_db():
    -    """Get MongoDB database connection"""
    -    from pymongo import MongoClient
    -    from flask import current_app
    -    client = MongoClient(current_app.config['MONGODB_URI'])
    -    return client.openlearnx
    +from services.real_compiler_service import real_compiler_service
     
    -@bp.route('/execute', methods=['POST', 'OPTIONS'])
    -def execute_code():
    -    """Execute code in specified language with Docker support"""
    -    if request.method == "OPTIONS":
    -        response = jsonify({'status': 'ok'})
    -        response.headers.add("Access-Control-Allow-Origin", "*")
    -        response.headers.add("Access-Control-Allow-Headers", "Content-Type,Authorization")
    -        response.headers.add("Access-Control-Allow-Methods", "POST,OPTIONS")
    -        return response
    -    
    -    try:
    -        data = request.get_json()
    -        language = data.get('language', 'python').lower()
    -        code = data.get('code', '').strip()
    -        input_data = data.get('input', '')
    -        
    -        print(f"🔧 Executing {language} code")
    -        print(f"📝 Code length: {len(code)} characters")
    -        
    -        if not code:
    -            return jsonify({"success": False, "error": "No code provided"}), 400
    -        
    -        # Execute based on language
    -        if language == 'python':
    -            return execute_python(code, input_data)
    -        elif language == 'java':
    -            return execute_java(code, input_data)
    -        elif language == 'javascript' or language == 'js':
    -            return execute_javascript(code, input_data)
    -        elif language == 'cpp' or language == 'c++':
    -            return execute_cpp(code, input_data)
    -        elif language == 'c':
    -            return execute_c(code, input_data)
    -        else:
    -            return jsonify({
    -                "success": False, 
    -                "error": f"Language '{language}' not supported. Available: python, java, javascript, cpp, c"
    -            }), 400
    -            
    -    except Exception as e:
    -        print(f"❌ Compiler error: {str(e)}")
    -        import traceback
    -        traceback.print_exc()
    -        return jsonify({"success": False, "error": f"Server error: {str(e)}"}), 500
    +bp = Blueprint("compiler", __name__)
    +
    +mongo_uri = os.getenv("MONGODB_URI", "mongodb://localhost:27017/")
    +client = MongoClient(mongo_uri)
    +db = client.openlearnx
    +
    +
    +def _json_response(payload, status=200):
    +    response = jsonify(payload)
    +    response.headers.add("Access-Control-Allow-Origin", "*")
    +    response.headers.add("Access-Control-Allow-Headers", "Content-Type,Authorization")
    +    response.headers.add("Access-Control-Allow-Methods", "GET,POST,OPTIONS")
    +    return response, status
    +
    +
    +def _client_ip():
    +    forwarded_for = request.headers.get("X-Forwarded-For", "")
    +    if forwarded_for:
    +        return forwarded_for.split(",")[0].strip()
    +    return request.remote_addr or "unknown"
     
    -def execute_python(code, input_data=""):
    -    """Execute Python code"""
    -    try:
    -        # Create temporary file
    -        with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
    -            f.write(code)
    -            temp_file = f.name
    -        
    -        try:
    -            # Execute with subprocess
    -            start_time = time.time()
    -            result = subprocess.run(
    -                ['python3', temp_file],
    -                input=input_data,
    -                text=True,
    -                capture_output=True,
    -                timeout=10,  # 10 second timeout
    -                cwd=tempfile.gettempdir()
    -            )
    -            execution_time = time.time() - start_time
    -            
    -            if result.returncode == 0:
    -                return jsonify({
    -                    "success": True,
    -                    "output": result.stdout or "Code executed successfully (no output)",
    -                    "error": result.stderr if result.stderr else None,
    -                    "language": "python",
    -                    "execution_time": round(execution_time, 3)
    -                })
    -            else:
    -                return jsonify({
    -                    "success": False,
    -                    "error": result.stderr or f"Process exited with code {result.returncode}",
    -                    "language": "python"
    -                })
    -                
    -        finally:
    -            # Clean up temp file
    -            try:
    -                os.unlink(temp_file)
    -            except:
    -                pass
    -                
    -    except subprocess.TimeoutExpired:
    -        return jsonify({
    -            "success": False, 
    -            "error": "Code execution timed out (10s limit)"
    -        }), 400
    -    except FileNotFoundError:
    -        return jsonify({
    -            "success": False, 
    -            "error": "Python interpreter not found. Please install Python 3."
    -        }), 500
    -    except Exception as e:
    -        return jsonify({
    -            "success": False, 
    -            "error": f"Python execution error: {str(e)}"
    -        }), 500
     
    -def execute_java(code, input_data=""):
    -    """Execute Java code"""
    +def _log_security(event_type, action, severity="info", status_code=200, metadata=None):
         try:
    -        # Extract class name from code
    -        import re
    -        class_match = re.search(r'public\s+class\s+(\w+)', code)
    -        if not class_match:
    -            return jsonify({
    -                "success": False,
    -                "error": "No public class found. Java code must contain 'public class ClassName'"
    -            }), 400
    -        
    -        class_name = class_match.group(1)
    -        
    -        # Create temporary directory
    -        temp_dir = tempfile.mkdtemp()
    -        java_file = os.path.join(temp_dir, f"{class_name}.java")
    -        
    -        try:
    -            # Write Java code to file
    -            with open(java_file, 'w') as f:
    -                f.write(code)
    -            
    -            # Compile Java code
    -            compile_result = subprocess.run(
    -                ['javac', java_file],
    -                capture_output=True,
    -                text=True,
    -                timeout=30,
    -                cwd=temp_dir
    -            )
    -            
    -            if compile_result.returncode != 0:
    -                return jsonify({
    -                    "success": False,
    -                    "error": f"Compilation error:\n{compile_result.stderr}",
    -                    "language": "java"
    -                })
    -            
    -            # Execute Java code
    -            start_time = time.time()
    -            result = subprocess.run(
    -                ['java', class_name],
    -                input=input_data,
    -                text=True,
    -                capture_output=True,
    -                timeout=10,
    -                cwd=temp_dir
    -            )
    -            execution_time = time.time() - start_time
    -            
    -            if result.returncode == 0:
    -                return jsonify({
    -                    "success": True,
    -                    "output": result.stdout or "Code executed successfully (no output)",
    -                    "error": result.stderr if result.stderr else None,
    -                    "language": "java",
    -                    "execution_time": round(execution_time, 3)
    -                })
    -            else:
    -                return jsonify({
    -                    "success": False,
    -                    "error": result.stderr or f"Runtime error (exit code {result.returncode})",
    -                    "language": "java"
    -                })
    -                
    -        finally:
    -            # Clean up temp files
    -            import shutil
    -            try:
    -                shutil.rmtree(temp_dir)
    -            except:
    -                pass
    -                
    -    except subprocess.TimeoutExpired:
    -        return jsonify({
    -            "success": False, 
    -            "error": "Code execution timed out"
    -        }), 400
    -    except FileNotFoundError:
    -        return jsonify({
    -            "success": False, 
    -            "error": "Java compiler/runtime not found. Please install JDK."
    -        }), 500
    +        log_doc = {
    +            "timestamp": datetime.utcnow(),
    +            "event_type": event_type,
    +            "action": action,
    +            "status_code": int(status_code),
    +            "severity": severity,
    +            "path": request.path,
    +            "method": request.method,
    +            "ip": _client_ip(),
    +            "user_agent": request.headers.get("User-Agent", ""),
    +            "metadata": metadata or {},
    +            "metadata_text": str(metadata or {}),
    +        }
    +        db.security_logs.insert_one(log_doc)
         except Exception as e:
    -        return jsonify({
    -            "success": False, 
    -            "error": f"Java execution error: {str(e)}"
    -        }), 500
    +        print(f"Compiler security log failure: {e}")
    +
    +
    +@bp.route("/execute", methods=["POST", "OPTIONS"])
    +def execute_code():
    +    if request.method == "OPTIONS":
    +        return _json_response({"status": "ok"}, 200)
     
    -def execute_javascript(code, input_data=""):
    -    """Execute JavaScript code"""
         try:
    -        # Create temporary file
    -        with tempfile.NamedTemporaryFile(mode='w', suffix='.js', delete=False) as f:
    -            # Add input handling if needed
    -            if input_data:
    -                js_code = f"""
    -const input = `{input_data}`;
    -const readline = {{ question: () => input }};
    -{code}
    -"""
    -            else:
    -                js_code = code
    -            
    -            f.write(js_code)
    -            temp_file = f.name
    -        
    -        try:
    -            # Execute with Node.js
    -            start_time = time.time()
    -            result = subprocess.run(
    -                ['node', temp_file],
    -                input=input_data,
    -                text=True,
    -                capture_output=True,
    -                timeout=10,
    -                cwd=tempfile.gettempdir()
    +        data = request.get_json(silent=True) or {}
    +        language = str(data.get("language", "python")).strip().lower()
    +        code = str(data.get("code", ""))
    +        input_data = str(data.get("input", ""))
    +
    +        if not code.strip():
    +            _log_security(
    +                "compiler_input_invalid",
    +                "empty_code_submission",
    +                severity="warning",
    +                status_code=400,
    +                metadata={"language": language},
                 )
    -            execution_time = time.time() - start_time
    -            
    -            if result.returncode == 0:
    -                return jsonify({
    -                    "success": True,
    -                    "output": result.stdout or "Code executed successfully (no output)",
    -                    "error": result.stderr if result.stderr else None,
    -                    "language": "javascript",
    -                    "execution_time": round(execution_time, 3)
    -                })
    -            else:
    -                return jsonify({
    -                    "success": False,
    -                    "error": result.stderr or f"Runtime error (exit code {result.returncode})",
    -                    "language": "javascript"
    -                })
    -                
    -        finally:
    -            try:
    -                os.unlink(temp_file)
    -            except:
    -                pass
    -                
    -    except subprocess.TimeoutExpired:
    -        return jsonify({
    -            "success": False, 
    -            "error": "Code execution timed out"
    -        }), 400
    -    except FileNotFoundError:
    -        return jsonify({
    -            "success": False, 
    -            "error": "Node.js not found. Please install Node.js."
    -        }), 500
    -    except Exception as e:
    -        return jsonify({
    -            "success": False, 
    -            "error": f"JavaScript execution error: {str(e)}"
    -        }), 500
    +            return _json_response({"success": False, "error": "No code provided"}, 400)
    +
    +        result = real_compiler_service.execute_code(code=code, language=language, input_data=input_data)
    +
    +        log_metadata = {
    +            "language": language,
    +            "code_size": len(code),
    +            "execution_id": result.get("execution_id"),
    +            "exit_code": result.get("exit_code"),
    +            "execution_time": result.get("execution_time", 0),
    +            "memory_used": result.get("memory_used", 0),
    +            "blocked": bool(result.get("blocked")),
    +            "security_violations": result.get("security_violations", []),
    +            "error": result.get("error", ""),
    +        }
     
    -def execute_cpp(code, input_data=""):
    -    """Execute C++ code"""
    -    try:
    -        # Create temporary files
    -        temp_dir = tempfile.mkdtemp()
    -        cpp_file = os.path.join(temp_dir, "main.cpp")
    -        exe_file = os.path.join(temp_dir, "main.exe") if os.name == 'nt' else os.path.join(temp_dir, "main")
    -        
             try:
    -            # Write C++ code to file
    -            with open(cpp_file, 'w') as f:
    -                f.write(code)
    -            
    -            # Compile C++ code
    -            compile_cmd = ['g++', '-o', exe_file, cpp_file, '-std=c++17']
    -            compile_result = subprocess.run(
    -                compile_cmd,
    -                capture_output=True,
    -                text=True,
    -                timeout=30,
    -                cwd=temp_dir
    -            )
    -            
    -            if compile_result.returncode != 0:
    -                return jsonify({
    -                    "success": False,
    -                    "error": f"Compilation error:\n{compile_result.stderr}",
    -                    "language": "cpp"
    -                })
    -            
    -            # Execute compiled program
    -            start_time = time.time()
    -            result = subprocess.run(
    -                [exe_file],
    -                input=input_data,
    -                text=True,
    -                capture_output=True,
    -                timeout=10,
    -                cwd=temp_dir
    +            status = "success"
    +            if result.get("blocked"):
    +                status = "blocked"
    +            elif result.get("error") and not result.get("success", False):
    +                status = "failed"
    +
    +            request_payload = {
    +                "language": language,
    +                "code": code[:4000],
    +                "code_size": len(code),
    +                "input": input_data[:2000],
    +                "input_size": len(input_data),
    +            }
    +            response_payload = {
    +                "success": bool(result.get("success")),
    +                "blocked": bool(result.get("blocked")),
    +                "execution_id": result.get("execution_id"),
    +                "output": (result.get("output") or "")[:4000],
    +                "error": result.get("error", ""),
    +                "security_violations": result.get("security_violations", []),
    +                "execution_time": result.get("execution_time", 0),
    +                "memory_used": result.get("memory_used", 0),
    +                "exit_code": result.get("exit_code", 0),
    +            }
    +
    +            db.code_execution_events.insert_one(
    +                {
    +                    "timestamp": datetime.utcnow(),
    +                    "event_type": "execution",
    +                    "source": "compiler",
    +                    "language": language,
    +                    "execution_id": result.get("execution_id"),
    +                    "execution_time": result.get("execution_time", 0),
    +                    "memory_used": result.get("memory_used", 0),
    +                    "exit_code": result.get("exit_code", 0),
    +                    "status": status,
    +                    "blocked": bool(result.get("blocked")),
    +                    "security_violations": result.get("security_violations", []),
    +                    "error": result.get("error", ""),
    +                    "request_body": request_payload,
    +                    "response_body": response_payload,
    +                    "ip": _client_ip(),
    +                    "user_agent": request.headers.get("User-Agent", ""),
    +                }
                 )
    -            execution_time = time.time() - start_time
    -            
    -            if result.returncode == 0:
    -                return jsonify({
    -                    "success": True,
    -                    "output": result.stdout or "Code executed successfully (no output)",
    -                    "error": result.stderr if result.stderr else None,
    -                    "language": "cpp",
    -                    "execution_time": round(execution_time, 3)
    -                })
    -            else:
    -                return jsonify({
    -                    "success": False,
    -                    "error": result.stderr or f"Runtime error (exit code {result.returncode})",
    -                    "language": "cpp"
    -                })
    -                
    -        finally:
    -            # Clean up temp files
    -            import shutil
    -            try:
    -                shutil.rmtree(temp_dir)
    -            except:
    -                pass
    -                
    -    except subprocess.TimeoutExpired:
    -        return jsonify({
    -            "success": False, 
    -            "error": "Code execution timed out"
    -        }), 400
    -    except FileNotFoundError:
    -        return jsonify({
    -            "success": False, 
    -            "error": "G++ compiler not found. Please install GCC/G++."
    -        }), 500
    -    except Exception as e:
    -        return jsonify({
    -            "success": False, 
    -            "error": f"C++ execution error: {str(e)}"
    -        }), 500
    +        except Exception:
    +            pass
     
    -def execute_c(code, input_data=""):
    -    """Execute C code"""
    -    try:
    -        # Create temporary files
    -        temp_dir = tempfile.mkdtemp()
    -        c_file = os.path.join(temp_dir, "main.c")
    -        exe_file = os.path.join(temp_dir, "main.exe") if os.name == 'nt' else os.path.join(temp_dir, "main")
    -        
    -        try:
    -            # Write C code to file
    -            with open(c_file, 'w') as f:
    -                f.write(code)
    -            
    -            # Compile C code
    -            compile_cmd = ['gcc', '-o', exe_file, c_file, '-std=c99']
    -            compile_result = subprocess.run(
    -                compile_cmd,
    -                capture_output=True,
    -                text=True,
    -                timeout=30,
    -                cwd=temp_dir
    +        if result.get("blocked"):
    +            _log_security(
    +                "compiler_security_block",
    +                "static_policy_blocked_submission",
    +                severity="warning",
    +                status_code=400,
    +                metadata=log_metadata,
                 )
    -            
    -            if compile_result.returncode != 0:
    -                return jsonify({
    -                    "success": False,
    -                    "error": f"Compilation error:\n{compile_result.stderr}",
    -                    "language": "c"
    -                })
    -            
    -            # Execute compiled program
    -            start_time = time.time()
    -            result = subprocess.run(
    -                [exe_file],
    -                input=input_data,
    -                text=True,
    -                capture_output=True,
    -                timeout=10,
    -                cwd=temp_dir
    +            return _json_response({"success": False, **result}, 400)
    +
    +        if result.get("error") and not result.get("success", False):
    +            _log_security(
    +                "compiler_execution_failed",
    +                "secure_container_execution_failed",
    +                severity="warning",
    +                status_code=400,
    +                metadata=log_metadata,
                 )
    -            execution_time = time.time() - start_time
    -            
    -            if result.returncode == 0:
    -                return jsonify({
    -                    "success": True,
    -                    "output": result.stdout or "Code executed successfully (no output)",
    -                    "error": result.stderr if result.stderr else None,
    -                    "language": "c",
    -                    "execution_time": round(execution_time, 3)
    -                })
    -            else:
    -                return jsonify({
    -                    "success": False,
    -                    "error": result.stderr or f"Runtime error (exit code {result.returncode})",
    -                    "language": "c"
    -                })
    -                
    -        finally:
    -            # Clean up temp files
    -            import shutil
    -            try:
    -                shutil.rmtree(temp_dir)
    -            except:
    -                pass
    -                
    -    except subprocess.TimeoutExpired:
    -        return jsonify({
    -            "success": False, 
    -            "error": "Code execution timed out"
    -        }), 400
    -    except FileNotFoundError:
    -        return jsonify({
    -            "success": False, 
    -            "error": "GCC compiler not found. Please install GCC."
    -        }), 500
    +            return _json_response({"success": False, **result}, 400)
    +
    +        _log_security(
    +            "compiler_execution_success",
    +            "secure_container_execution_completed",
    +            severity="info",
    +            status_code=200,
    +            metadata=log_metadata,
    +        )
    +
    +        return _json_response(result, 200)
    +
         except Exception as e:
    -        return jsonify({
    -            "success": False, 
    -            "error": f"C execution error: {str(e)}"
    -        }), 500
    +        _log_security(
    +            "compiler_internal_error",
    +            "compiler_route_exception",
    +            severity="error",
    +            status_code=500,
    +            metadata={"error": str(e)},
    +        )
    +        return _json_response({"success": False, "error": f"Server error: {str(e)}"}, 500)
     
    -@bp.route('/languages', methods=['GET', 'OPTIONS'])
    +
    +@bp.route("/languages", methods=["GET", "OPTIONS"])
     def get_supported_languages():
    -    """Get list of supported programming languages"""
         if request.method == "OPTIONS":
    -        response = jsonify({'status': 'ok'})
    -        response.headers.add("Access-Control-Allow-Origin", "*")
    -        response.headers.add("Access-Control-Allow-Headers", "Content-Type,Authorization")  
    -        response.headers.add("Access-Control-Allow-Methods", "GET,OPTIONS")
    -        return response
    -    
    +        return _json_response({"status": "ok"}, 200)
    +
         try:
    -        languages = {
    -            "python": {
    -                "name": "Python",
    -                "version": "3.x",
    -                "extension": ".py",
    -                "available": check_language_availability("python3")
    -            },
    -            "java": {
    -                "name": "Java",
    -                "version": "JDK 8+",
    -                "extension": ".java",
    -                "available": check_language_availability("javac")
    -            },
    -            "javascript": {
    -                "name": "JavaScript",
    -                "version": "Node.js",
    -                "extension": ".js",
    -                "available": check_language_availability("node")
    -            },
    -            "cpp": {
    -                "name": "C++",
    -                "version": "GCC/G++",
    -                "extension": ".cpp",
    -                "available": check_language_availability("g++")
    -            },
    -            "c": {
    -                "name": "C",
    -                "version": "GCC",
    -                "extension": ".c",
    -                "available": check_language_availability("gcc")
    -            }
    -        }
    -        
    -        return jsonify({
    -            "success": True,
    -            "languages": languages,
    -            "total": len(languages),
    -            "available_count": sum(1 for lang in languages.values() if lang["available"])
    -        })
    -        
    +        return _json_response({"success": True, "languages": real_compiler_service.get_supported_languages()}, 200)
         except Exception as e:
    -        return jsonify({"success": False, "error": str(e)}), 500
    +        return _json_response({"success": False, "error": str(e)}, 500)
     
    -def check_language_availability(command):
    -    """Check if a language compiler/interpreter is available"""
    -    try:
    -        result = subprocess.run([command, '--version'], 
    -                              capture_output=True, 
    -                              timeout=5)
    -        return result.returncode == 0
    -    except (FileNotFoundError, subprocess.TimeoutExpired):
    -        return False
    -
    -@bp.route('/health', methods=['GET'])
    +
    +@bp.route("/test", methods=["POST", "OPTIONS"])
    +def compiler_test():
    +    if request.method == "OPTIONS":
    +        return _json_response({"status": "ok"}, 200)
    +
    +    data = request.get_json(silent=True) or {}
    +    language = str(data.get("language", "python")).strip().lower()
    +
    +    smoke_code = {
    +        "python": 'print("ok")',
    +        "javascript": 'console.log("ok")',
    +        "java": "public class Main { public static void main(String[] args){ System.out.println(\"ok\"); } }",
    +        "c": "#include <stdio.h>\nint main(){ printf(\"ok\\n\"); return 0; }",
    +        "cpp": "#include <iostream>\nint main(){ std::cout << \"ok\\n\"; return 0; }",
    +        "go": "package main\nimport \"fmt\"\nfunc main(){ fmt.Println(\"ok\") }",
    +        "rust": "fn main(){ println!(\"ok\"); }",
    +    }
    +
    +    if language not in smoke_code:
    +        return _json_response({"success": False, "error": f"Unsupported language: {language}"}, 400)
    +
    +    result = real_compiler_service.execute_code(smoke_code[language], language, "")
    +    if result.get("success"):
    +        return _json_response(result, 200)
    +    return _json_response({"success": False, **result}, 400)
    +
    +
    +@bp.route("/health", methods=["GET"])
     def compiler_health():
    -    """Health check for compiler service"""
    -    try:
    -        languages_status = {
    -            "python": check_language_availability("python3"),
    -            "java": check_language_availability("javac"),
    -            "javascript": check_language_availability("node"),
    -            "cpp": check_language_availability("g++"),
    -            "c": check_language_availability("gcc")
    -        }
    -        
    -        available_languages = sum(languages_status.values())
    -        total_languages = len(languages_status)
    -        
    -        status = "healthy" if available_languages > 0 else "unavailable"
    -        
    -        return jsonify({
    -            "status": status,
    -            "timestamp": datetime.now().isoformat(),
    -            "languages": languages_status,
    -            "available_languages": available_languages,
    -            "total_languages": total_languages,
    -            "docker_available": check_docker_availability()
    -        })
    -        
    -    except Exception as e:
    -        return jsonify({
    -            "status": "error",
    -            "error": str(e),
    -            "timestamp": datetime.now().isoformat()
    -        }), 500
    -
    -def check_docker_availability():
    -    """Check if Docker is available for containerized execution"""
    -    try:
    -        client = docker.from_env()
    -        client.ping()
    -        return True
    -    except:
    -        return False
    +    docker_ok = real_compiler_service._get_docker_client() is not None and real_compiler_service.docker_available
    +    return _json_response(
    +        {
    +            "status": "healthy" if docker_ok else "degraded",
    +            "timestamp": datetime.utcnow().isoformat(),
    +            "docker_available": docker_ok,
    +            "secure_execution_only": True,
    +            "supported_languages": [l["id"] for l in real_compiler_service.get_supported_languages()],
    +        },
    +        200 if docker_ok else 503,
    +    )
    
  • backend/services/real_compiler_service.py+418 223 modified
    @@ -1,117 +1,198 @@
    -import docker
    -import tempfile
    +import ast
     import os
    -import subprocess
    +import queue
    +import re
    +import tempfile
    +import threading
     import time
     import uuid
    -import json
    -import threading
    -from typing import Dict, List, Any, Optional
     from datetime import datetime
    -import queue
    -import signal
    +from typing import Any, Dict, List, Optional, Tuple
    +
    +import docker
    +
     
     class RealCompilerService:
         def __init__(self):
    -        self.client = None  # Lazy initialization
    +        self.client = None
             self.execution_queue = queue.Queue()
    -        self.active_executions = {}
    -        self.max_concurrent_executions = 5
    +        self.active_executions: Dict[str, Dict[str, Any]] = {}
    +        self.max_code_size = 20000
             self.docker_available = False
    -        
    -        # Enhanced language configurations with real execution
    +
    +        # Docker is mandatory for secure execution.
             self.language_configs = {
    -            'python': {
    -                'image': 'python:3.11-slim',
    -                'file_ext': '.py',
    -                'compile_command': None,  # Python doesn't need compilation
    -                'run_command': 'python /app/code.py',
    -                'timeout': 30,
    -                'memory_limit': '256m',
    -                'cpu_limit': '0.5'
    +            "python": {
    +                "image": "python:3.11-alpine",
    +                "file_name": "code.py",
    +                "compile_command": None,
    +                "run_command": "python /workspace/code.py",
    +                "timeout": 8,
    +                "memory_limit": "128m",
    +                "cpu_limit": 0.35,
                 },
    -            'java': {
    -                'image': 'openjdk:17-alpine',
    -                'file_ext': '.java',
    -                'compile_command': 'javac /app/Main.java',
    -                'run_command': 'java -cp /app Main',
    -                'timeout': 30,
    -                'memory_limit': '512m',
    -                'cpu_limit': '0.5'
    +            "javascript": {
    +                "image": "node:20-alpine",
    +                "file_name": "code.js",
    +                "compile_command": None,
    +                "run_command": "node /workspace/code.js",
    +                "timeout": 8,
    +                "memory_limit": "128m",
    +                "cpu_limit": 0.35,
                 },
    -            'cpp': {
    -                'image': 'gcc:latest',
    -                'file_ext': '.cpp',
    -                'compile_command': 'g++ -o /app/program /app/code.cpp -std=c++17',
    -                'run_command': '/app/program',
    -                'timeout': 30,
    -                'memory_limit': '256m',
    -                'cpu_limit': '0.5'
    +            "c": {
    +                "image": "gcc:13",
    +                "file_name": "code.c",
    +                "compile_command": "gcc -O2 -o /workspace/program /workspace/code.c",
    +                "run_command": "/workspace/program",
    +                "timeout": 10,
    +                "memory_limit": "192m",
    +                "cpu_limit": 0.5,
                 },
    -            'c': {
    -                'image': 'gcc:latest',
    -                'file_ext': '.c',
    -                'compile_command': 'gcc -o /app/program /app/code.c',
    -                'run_command': '/app/program',
    -                'timeout': 30,
    -                'memory_limit': '256m',
    -                'cpu_limit': '0.5'
    +            "cpp": {
    +                "image": "gcc:13",
    +                "file_name": "code.cpp",
    +                "compile_command": "g++ -O2 -std=c++17 -o /workspace/program /workspace/code.cpp",
    +                "run_command": "/workspace/program",
    +                "timeout": 10,
    +                "memory_limit": "256m",
    +                "cpu_limit": 0.5,
                 },
    -            'javascript': {
    -                'image': 'node:18-alpine',
    -                'file_ext': '.js',
    -                'compile_command': None,
    -                'run_command': 'node /app/code.js',
    -                'timeout': 30,
    -                'memory_limit': '256m',
    -                'cpu_limit': '0.5'
    +            "java": {
    +                "image": "openjdk:17-alpine",
    +                "file_name": "Main.java",
    +                "compile_command": "javac /workspace/Main.java",
    +                "run_command": "java -cp /workspace Main",
    +                "timeout": 12,
    +                "memory_limit": "256m",
    +                "cpu_limit": 0.5,
                 },
    -            'bash': {
    -                'image': 'bash:5.2-alpine3.18',
    -                'file_ext': '.sh',
    -                'compile_command': None,
    -                'run_command': 'bash /app/code.sh',
    -                'timeout': 30,
    -                'memory_limit': '128m',
    -                'cpu_limit': '0.3'
    +            "go": {
    +                "image": "golang:1.22-alpine",
    +                "file_name": "code.go",
    +                "compile_command": "go build -o /workspace/program /workspace/code.go",
    +                "run_command": "/workspace/program",
    +                "timeout": 14,
    +                "memory_limit": "256m",
    +                "cpu_limit": 0.6,
                 },
    -            'go': {
    -                'image': 'golang:1.21-alpine',
    -                'file_ext': '.go',
    -                'compile_command': 'go build -o /app/program /app/code.go',
    -                'run_command': '/app/program',
    -                'timeout': 30,
    -                'memory_limit': '512m',
    -                'cpu_limit': '0.5'
    +            "rust": {
    +                "image": "rust:1.77-alpine",
    +                "file_name": "code.rs",
    +                "compile_command": "rustc /workspace/code.rs -o /workspace/program",
    +                "run_command": "/workspace/program",
    +                "timeout": 20,
    +                "memory_limit": "512m",
    +                "cpu_limit": 0.8,
                 },
    -            'rust': {
    -                'image': 'rust:1.75-alpine',
    -                'file_ext': '.rs',
    -                'compile_command': 'rustc /app/code.rs -o /app/program',
    -                'run_command': '/app/program',
    -                'timeout': 60,  # Rust compilation can be slow
    -                'memory_limit': '1g',
    -                'cpu_limit': '1.0'
    -            }
             }
    -        
    -        # Start execution worker
    +
    +        self.blocked_python_modules = {
    +            "os",
    +            "socket",
    +            "subprocess",
    +            "pty",
    +            "multiprocessing",
    +            "ctypes",
    +            "resource",
    +            "pwd",
    +            "grp",
    +            "signal",
    +            "fcntl",
    +            "selectors",
    +            "pathlib",
    +            "shutil",
    +        }
    +        self.blocked_python_calls = {
    +            "eval",
    +            "exec",
    +            "compile",
    +            "__import__",
    +            "open",
    +            "input",
    +            "globals",
    +            "locals",
    +            "vars",
    +            "getattr",
    +            "setattr",
    +            "delattr",
    +        }
    +        self.blocked_python_attrs = {
    +            "fork",
    +            "forkpty",
    +            "spawn",
    +            "spawnl",
    +            "spawnlp",
    +            "spawnv",
    +            "spawnvp",
    +            "system",
    +            "popen",
    +            "execl",
    +            "execle",
    +            "execlp",
    +            "execv",
    +            "execve",
    +            "execvp",
    +            "setsid",
    +            "dup2",
    +        }
    +        self.blocked_patterns = {
    +            "javascript": [
    +                r"require\s*\(\s*['\"]child_process['\"]\s*\)",
    +                r"require\s*\(\s*['\"]net['\"]\s*\)",
    +                r"require\s*\(\s*['\"]dgram['\"]\s*\)",
    +                r"process\.env",
    +                r"process\.binding",
    +                r"fs\.readFile|fs\.writeFile|fs\.open|fs\.create",
    +            ],
    +            "java": [
    +                r"Runtime\.getRuntime\s*\(",
    +                r"ProcessBuilder\s*\(",
    +                r"java\.net\.",
    +                r"java\.nio\.file\.",
    +                r"System\.getenv\s*\(",
    +            ],
    +            "c": [
    +                r"\bsystem\s*\(",
    +                r"\bpopen\s*\(",
    +                r"\bfork\s*\(",
    +                r"\bexec[a-z]*\s*\(",
    +                r"\bsocket\s*\(",
    +            ],
    +            "cpp": [
    +                r"\bsystem\s*\(",
    +                r"\bpopen\s*\(",
    +                r"\bfork\s*\(",
    +                r"\bexec[a-z]*\s*\(",
    +                r"\bsocket\s*\(",
    +            ],
    +            "go": [
    +                r"\bexec\.Command\s*\(",
    +                r"\bnet\.",
    +                r"\bos\.StartProcess\s*\(",
    +                r"\bos\.Exec\s*\(",
    +            ],
    +            "rust": [
    +                r"std::process::Command",
    +                r"std::net::",
    +                r"unsafe\s*\{",
    +            ],
    +        }
    +
             self.start_execution_worker()
     
         def _get_docker_client(self):
    -        """Lazily initialize Docker client"""
             if self.client is None:
                 try:
                     self.client = docker.from_env()
    +                self.client.ping()
                     self.docker_available = True
    -            except Exception as e:
    -                print(f"⚠️ Docker initialization failed: {e}")
    +            except Exception:
                     self.docker_available = False
                     self.client = None
             return self.client
     
         def start_execution_worker(self):
    -        """Start background worker for code execution"""
             def worker():
                 while True:
                     try:
    @@ -122,212 +203,326 @@ def worker():
                         continue
                     except Exception as e:
                         print(f"Execution worker error: {e}")
    -        
    +
             worker_thread = threading.Thread(target=worker, daemon=True)
             worker_thread.start()
     
    -    def execute_code(self, code: str, language: str, input_data: str = "", 
    -                    execution_id: str = None) -> Dict[str, Any]:
    -        """Execute code with real output capture"""
    +    def _execute_task(self, _execution_task):
    +        # Queue worker placeholder kept for backward compatibility.
    +        return None
    +
    +    def execute_code(self, code: str, language: str, input_data: str = "", execution_id: str = None) -> Dict[str, Any]:
    +        language = (language or "").lower().strip()
    +        if language == "js":
    +            language = "javascript"
    +        if language == "c++":
    +            language = "cpp"
    +
             if language not in self.language_configs:
                 return {"error": f"Language '{language}' not supported"}
    -        
    +
             if not execution_id:
                 execution_id = str(uuid.uuid4())
    -        
    +
    +        if not code or not code.strip():
    +            return {"error": "No code provided", "execution_id": execution_id, "language": language}
    +
    +        if len(code) > self.max_code_size:
    +            return {
    +                "error": f"Code too large. Maximum size is {self.max_code_size} characters.",
    +                "execution_id": execution_id,
    +                "language": language,
    +                "blocked": True,
    +            }
    +
    +        ok, violations = self._validate_code_static(code, language)
    +        if not ok:
    +            return {
    +                "error": "Code rejected by security policy",
    +                "execution_id": execution_id,
    +                "language": language,
    +                "blocked": True,
    +                "security_violations": violations,
    +            }
    +
             config = self.language_configs[language]
    -        
    +        execution_context = {
    +            "execution_id": execution_id,
    +            "code": code,
    +            "language": language,
    +            "input_data": input_data or "",
    +            "config": config,
    +            "start_time": datetime.utcnow(),
    +            "status": "running",
    +        }
    +
             try:
    -            # Create execution context
    -            execution_context = {
    -                'execution_id': execution_id,
    -                'code': code,
    -                'language': language,
    -                'input_data': input_data,
    -                'config': config,
    -                'start_time': datetime.now(),
    -                'status': 'running'
    -            }
    -            
                 self.active_executions[execution_id] = execution_context
    -            
    -            # Execute in Docker container
                 result = self._execute_in_container(execution_context)
    -            
    -            # Update execution context
    -            execution_context['status'] = 'completed'
    -            execution_context['end_time'] = datetime.now()
    -            execution_context['result'] = result
    -            
    +            execution_context["status"] = "completed"
    +            execution_context["end_time"] = datetime.utcnow()
    +            execution_context["result"] = result
    +
    +            if result.get("error"):
    +                return {
    +                    "success": False,
    +                    "execution_id": execution_id,
    +                    "output": result.get("output", ""),
    +                    "error": result.get("error", ""),
    +                    "execution_time": result.get("execution_time", 0),
    +                    "memory_used": result.get("memory_used", 0),
    +                    "exit_code": result.get("exit_code", -1),
    +                    "language": language,
    +                    "timestamp": datetime.utcnow().isoformat(),
    +                }
    +
                 return {
                     "success": True,
                     "execution_id": execution_id,
    -                "output": result.get('output', ''),
    -                "error": result.get('error', ''),
    -                "execution_time": result.get('execution_time', 0),
    -                "memory_used": result.get('memory_used', 0),
    -                "exit_code": result.get('exit_code', 0),
    +                "output": result.get("output", ""),
    +                "error": "",
    +                "execution_time": result.get("execution_time", 0),
    +                "memory_used": result.get("memory_used", 0),
    +                "exit_code": result.get("exit_code", 0),
                     "language": language,
    -                "timestamp": datetime.now().isoformat()
    +                "timestamp": datetime.utcnow().isoformat(),
                 }
    -            
             except Exception as e:
                 return {
                     "error": f"Execution failed: {str(e)}",
                     "execution_id": execution_id,
    -                "language": language
    +                "language": language,
                 }
             finally:
    -            # Clean up
    -            if execution_id in self.active_executions:
    -                del self.active_executions[execution_id]
    -
    -    def _execute_in_container(self, context: Dict) -> Dict[str, Any]:
    -        """Execute code in secure Docker container"""
    -        code = context['code']
    -        language = context['language']
    -        input_data = context['input_data']
    -        config = context['config']
    -        
    -        # Check Docker availability
    +            self.active_executions.pop(execution_id, None)
    +
    +    def _validate_code_static(self, code: str, language: str) -> Tuple[bool, List[str]]:
    +        violations: List[str] = []
    +
    +        # Generic payload patterns often used for sandbox escape and exfiltration.
    +        generic_patterns = [
    +            r"/bin/sh",
    +            r"/bin/bash",
    +            r"nc\s+-l|nc\s+-e",
    +            r"reverse\s*shell",
    +            r"bash\s+-i",
    +            r"wget\s+http|curl\s+http",
    +        ]
    +        for pattern in generic_patterns:
    +            if re.search(pattern, code, flags=re.IGNORECASE):
    +                violations.append(f"Blocked high-risk pattern: {pattern}")
    +
    +        if language == "python":
    +            try:
    +                tree = ast.parse(code)
    +            except SyntaxError as e:
    +                return False, [f"Python syntax error: {e}"]
    +
    +            for node in ast.walk(tree):
    +                if isinstance(node, ast.Import):
    +                    for alias in node.names:
    +                        base = alias.name.split(".")[0]
    +                        if base in self.blocked_python_modules:
    +                            violations.append(f"Blocked module import: {base}")
    +
    +                if isinstance(node, ast.ImportFrom):
    +                    if node.module:
    +                        base = node.module.split(".")[0]
    +                        if base in self.blocked_python_modules:
    +                            violations.append(f"Blocked module import: {base}")
    +
    +                if isinstance(node, ast.Call):
    +                    fn = node.func
    +                    if isinstance(fn, ast.Name) and fn.id in self.blocked_python_calls:
    +                        violations.append(f"Blocked function call: {fn.id}")
    +                    if isinstance(fn, ast.Attribute) and fn.attr in self.blocked_python_attrs:
    +                        violations.append(f"Blocked dangerous call: {fn.attr}")
    +
    +        for pattern in self.blocked_patterns.get(language, []):
    +            if re.search(pattern, code, flags=re.IGNORECASE | re.MULTILINE):
    +                violations.append(f"Blocked pattern for {language}: {pattern}")
    +
    +        return len(violations) == 0, violations
    +
    +    def _execute_in_container(self, context: Dict[str, Any]) -> Dict[str, Any]:
             docker_client = self._get_docker_client()
             if docker_client is None or not self.docker_available:
                 return {
                     "output": "",
    -                "error": "Docker service is not available. Compiler service cannot execute code.",
    +                "error": "Docker service is not available. Secure execution requires Docker.",
                     "exit_code": -1,
                     "execution_time": 0,
    -                "memory_used": 0
    +                "memory_used": 0,
                 }
    -        
    -        with tempfile.TemporaryDirectory() as temp_dir:
    -            # Prepare code file
    -            filename = f"code{config['file_ext']}" if language != 'java' else "Main.java"
    -            file_path = os.path.join(temp_dir, filename)
    -            
    -            with open(file_path, 'w', encoding='utf-8') as f:
    +
    +        code = context["code"]
    +        language = context["language"]
    +        input_data = context["input_data"]
    +        config = context["config"]
    +
    +        with tempfile.TemporaryDirectory(prefix="openlearnx_exec_") as temp_dir:
    +            os.chmod(temp_dir, 0o755)
    +            code_path = os.path.join(temp_dir, config["file_name"])
    +            with open(code_path, "w", encoding="utf-8") as f:
                     f.write(code)
    -            
    -            # Prepare input file
    -            input_file = os.path.join(temp_dir, 'input.txt')
    -            with open(input_file, 'w', encoding='utf-8') as f:
    +            os.chmod(code_path, 0o644)
    +
    +            input_path = os.path.join(temp_dir, "input.txt")
    +            with open(input_path, "w", encoding="utf-8") as f:
                     f.write(input_data)
    -            
    +            os.chmod(input_path, 0o644)
    +
    +            container = None
    +            start = time.time()
                 try:
    -                start_time = time.time()
    -                
    -                # Create and run container
    +                cpu_quota = int(float(config["cpu_limit"]) * 100000)
                     container = docker_client.containers.run(
    -                    config['image'],
    -                    command=self._build_execution_command(config, filename),
    -                    volumes={temp_dir: {'bind': '/app', 'mode': 'rw'}},
    -                    working_dir='/app',
    -                    mem_limit=config['memory_limit'],
    +                    config["image"],
    +                    command=self._build_execution_command(config),
    +                    volumes={temp_dir: {"bind": "/workspace", "mode": "rw"}},
    +                    working_dir="/workspace",
    +                    mem_limit=config["memory_limit"],
    +                    memswap_limit=config["memory_limit"],
                         cpu_period=100000,
    -                    cpu_quota=int(float(config['cpu_limit']) * 100000),
    -                    network_mode='none',  # No network access
    -                    remove=True,
    -                    detach=False,
    -                    stdin_open=True,
    +                    cpu_quota=cpu_quota,
    +                    pids_limit=64,
    +                    network_mode="none",
    +                    detach=True,
    +                    stdin_open=False,
                         tty=False,
    -                    timeout=config['timeout'],
    -                    # Security options
    -                    cap_drop=['ALL'],
    -                    security_opt=['no-new-privileges'],
    -                    read_only=False,
    -                    tmpfs={'/tmp': 'rw,noexec,nosuid,size=100m'}
    +                    cap_drop=["ALL"],
    +                    security_opt=["no-new-privileges:true"],
    +                    read_only=True,
    +                    user="65534:65534",
    +                    tmpfs={
    +                        "/tmp": "rw,noexec,nosuid,size=64m",
    +                    },
    +                    labels={
    +                        "openlearnx.sandbox": "true",
    +                        "openlearnx.execution_id": context["execution_id"],
    +                    },
                     )
    -                
    -                execution_time = time.time() - start_time
    -                output = container.decode('utf-8')
    -                
    +
    +                wait_result = container.wait(timeout=config["timeout"] + 2)
    +                logs = container.logs(stdout=True, stderr=True).decode("utf-8", errors="replace")
    +                status_code = int(wait_result.get("StatusCode", -1))
    +                execution_time = round(time.time() - start, 3)
    +                memory_used = self._get_memory_usage(container)
    +
    +                if status_code != 0:
    +                    return {
    +                        "output": "",
    +                        "error": self._sanitize_error_output(language, logs.strip() or f"Runtime exited with code {status_code}"),
    +                        "exit_code": status_code,
    +                        "execution_time": execution_time,
    +                        "memory_used": memory_used,
    +                    }
    +
                     return {
    -                    "output": output.strip(),
    +                    "output": logs.strip(),
                         "error": "",
                         "exit_code": 0,
    -                    "execution_time": round(execution_time, 3),
    -                    "memory_used": self._get_memory_usage(container)
    -                }
    -                
    -            except docker.errors.ContainerError as e:
    -                return {
    -                    "output": "",
    -                    "error": f"Runtime error (exit code {e.exit_status}): {e.stderr.decode('utf-8') if e.stderr else 'Unknown error'}",
    -                    "exit_code": e.exit_status,
    -                    "execution_time": time.time() - start_time,
    -                    "memory_used": 0
    -                }
    -            except docker.errors.APIError as e:
    -                return {
    -                    "output": "",
    -                    "error": f"Docker API error: {str(e)}",
    -                    "exit_code": -1,
    -                    "execution_time": 0,
    -                    "memory_used": 0
    +                    "execution_time": execution_time,
    +                    "memory_used": memory_used,
                     }
    +
                 except Exception as e:
    +                if container is not None:
    +                    try:
    +                        container.kill()
    +                    except Exception:
    +                        pass
                     return {
                         "output": "",
    -                    "error": f"Execution error: {str(e)}",
    +                    "error": self._sanitize_error_output(language, f"Execution failed or timed out: {str(e)}"),
                         "exit_code": -1,
    -                    "execution_time": 0,
    -                    "memory_used": 0
    +                    "execution_time": round(time.time() - start, 3),
    +                    "memory_used": 0,
                     }
    +            finally:
    +                if container is not None:
    +                    try:
    +                        container.remove(force=True)
    +                    except Exception:
    +                        pass
    +
    +    def _sanitize_error_output(self, language: str, raw_error: str) -> str:
    +        if not raw_error:
    +            return "Runtime error"
    +
    +        text = str(raw_error)
    +        # Avoid leaking container-internal paths.
    +        text = re.sub(r"/workspace/", "", text)
    +        lines = [line.rstrip() for line in text.splitlines() if line.strip()]
     
    -    def _build_execution_command(self, config: Dict, filename: str) -> str:
    -        """Build the execution command for the container"""
    -        commands = []
    -        
    -        # Add compilation step if needed
    -        if config.get('compile_command'):
    -            commands.append(config['compile_command'])
    -        
    -        # Add execution command with input redirection
    -        run_cmd = config['run_command']
    -        if '<' not in run_cmd:  # Add input redirection if not present
    -            run_cmd += ' < /app/input.txt 2>&1'
    -        commands.append(run_cmd)
    -        
    -        # Combine commands
    -        return f"sh -c '{' && '.join(commands)}'"
    +        if language == "python":
    +            cleaned: List[str] = []
    +            for line in lines:
    +                stripped = line.strip()
    +                if stripped.startswith("Traceback"):
    +                    continue
    +                if stripped.startswith("File "):
    +                    continue
    +                if stripped.startswith("^"):
    +                    continue
    +                cleaned.append(stripped)
    +
    +            for line in reversed(cleaned):
    +                if "Error" in line or "Exception" in line:
    +                    return line
    +            if cleaned:
    +                return cleaned[-1]
    +            return "Python runtime error"
    +
    +        # Keep non-python errors concise.
    +        tail = lines[-3:] if len(lines) > 3 else lines
    +        sanitized = "\n".join(tail).strip()
    +        return sanitized or "Runtime error"
    +
    +    def _build_execution_command(self, config: Dict[str, Any]) -> str:
    +        commands: List[str] = []
    +        if config.get("compile_command"):
    +            commands.append(config["compile_command"])
    +
    +        run_cmd = config["run_command"]
    +        if "< /workspace/input.txt" not in run_cmd:
    +            run_cmd = f"{run_cmd} < /workspace/input.txt"
    +
    +        # ulimit adds an additional in-container CPU-time and file-size restriction.
    +        shell_cmd = " && ".join(commands + [run_cmd])
    +        return f"sh -c 'ulimit -t {config['timeout']} -f 1024; {shell_cmd} 2>&1'"
     
         def _get_memory_usage(self, container) -> int:
    -        """Get memory usage from container stats"""
             try:
                 stats = container.stats(stream=False)
    -            memory_usage = stats['memory']['usage']
    -            return memory_usage
    -        except:
    +            return int(stats.get("memory_stats", {}).get("usage", 0))
    +        except Exception:
                 return 0
     
         def get_supported_languages(self) -> List[Dict[str, str]]:
    -        """Get list of supported languages with details"""
             return [
                 {
    -                'id': lang_id,
    -                'name': lang_id.title(),
    -                'extension': config['file_ext'],
    -                'timeout': config['timeout'],
    -                'memory_limit': config['memory_limit']
    +                "id": lang_id,
    +                "name": lang_id.title(),
    +                "extension": os.path.splitext(config["file_name"])[1],
    +                "timeout": config["timeout"],
    +                "memory_limit": config["memory_limit"],
                 }
                 for lang_id, config in self.language_configs.items()
             ]
     
    -    def get_execution_status(self, execution_id: str) -> Optional[Dict]:
    -        """Get status of a running execution"""
    +    def get_execution_status(self, execution_id: str) -> Optional[Dict[str, Any]]:
             return self.active_executions.get(execution_id)
     
         def cancel_execution(self, execution_id: str) -> bool:
    -        """Cancel a running execution"""
             if execution_id in self.active_executions:
    -            # Implementation would involve stopping the Docker container
                 del self.active_executions[execution_id]
                 return True
             return False
     
    -# Create global instance
    +
     try:
         real_compiler_service = RealCompilerService()
     except Exception as e:
    -    print(f"⚠️ Failed to initialize RealCompilerService: {e}")
    -    real_compiler_service = RealCompilerService()  # Still create instance for graceful fallback
    +    print(f"WARNING: Failed to initialize RealCompilerService: {e}")
    +    real_compiler_service = RealCompilerService()
    
  • frontend/app/admin/logs/page.tsx+273 7 modified
    @@ -23,6 +23,24 @@ type AdminLog = {
       origin?: string
     }
     
    +type ExecutionLog = {
    +  id: string
    +  timestamp: string
    +  source?: string
    +  language: string
    +  execution_id?: string
    +  status: string
    +  exit_code?: number
    +  execution_time?: number
    +  memory_used?: number
    +  blocked?: boolean
    +  error?: string
    +  ip?: string
    +  request_body?: unknown
    +  response_body?: unknown
    +  user_agent?: string
    +}
    +
     const API_BASE = "http://127.0.0.1:5000"
     
     export default function AdminLogsPage() {
    @@ -31,8 +49,11 @@ export default function AdminLogsPage() {
       const [loading, setLoading] = useState(false)
       const [exporting, setExporting] = useState(false)
       const [message, setMessage] = useState("")
    +  const [logView, setLogView] = useState<"security" | "execution">("security")
       const [logs, setLogs] = useState<AdminLog[]>([])
    +  const [executionLogs, setExecutionLogs] = useState<ExecutionLog[]>([])
       const [selectedLog, setSelectedLog] = useState<AdminLog | null>(null)
    +  const [selectedExecutionLog, setSelectedExecutionLog] = useState<ExecutionLog | null>(null)
     
       const safeJson = (value: unknown) => {
         if (value === null || value === undefined || value === "") return "No data"
    @@ -89,6 +110,12 @@ export default function AdminLogsPage() {
         search: "",
       })
       const [pagination, setPagination] = useState({ page: 1, limit: 50, total: 0, pages: 1 })
    +  const [executionFilters, setExecutionFilters] = useState({
    +    language: "",
    +    status: "",
    +    search: "",
    +  })
    +  const [executionPagination, setExecutionPagination] = useState({ page: 1, limit: 50, total: 0, pages: 1 })
     
       const getToken = () => localStorage.getItem("admin_token")
       const headers = () => {
    @@ -142,6 +169,34 @@ export default function AdminLogsPage() {
         }
       }
     
    +  const fetchExecutionLogs = async (page = 1, nextFilters = executionFilters) => {
    +    setLoading(true)
    +    setMessage("")
    +    const params = new URLSearchParams()
    +    params.set("page", String(page))
    +    params.set("limit", String(executionPagination.limit))
    +    if (nextFilters.language) params.set("language", nextFilters.language)
    +    if (nextFilters.status) params.set("status", nextFilters.status)
    +    if (nextFilters.search) params.set("search", nextFilters.search)
    +
    +    try {
    +      const resp = await fetch(`${API_BASE}/api/admin/logs/executions?${params.toString()}`, { headers: headers() })
    +      if (resp.ok) {
    +        const data = await resp.json()
    +        setExecutionLogs(Array.isArray(data.logs) ? data.logs : [])
    +        if (data.pagination) {
    +          setExecutionPagination(data.pagination)
    +        }
    +      } else {
    +        setExecutionLogs([])
    +      }
    +    } catch {
    +      setExecutionLogs([])
    +    } finally {
    +      setLoading(false)
    +    }
    +  }
    +
       const triggerDownload = (content: string, filename: string, mimeType: string) => {
         const blob = new Blob([content], { type: mimeType })
         const url = URL.createObjectURL(blob)
    @@ -212,11 +267,37 @@ export default function AdminLogsPage() {
       return (
         <div className="space-y-6">
           <div className="rounded-xl border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-800 dark:bg-gray-900">
    -        <h1 className="text-2xl font-semibold text-gray-900 dark:text-white">Security and Activity Logs</h1>
    +        <h1 className="text-2xl font-semibold text-gray-900 dark:text-white">Admin Logs</h1>
             <p className="mt-1 text-sm text-gray-600 dark:text-gray-400">
    -          Filter authentication, access-control, suspicious payload, and admin activity events.
    +          Switch between security/activity logs and a separate execution log stream.
             </p>
             <div className="mt-4 flex flex-wrap gap-2">
    +          <button
    +            onClick={() => {
    +              setLogView("security")
    +              setSelectedLog(null)
    +              setSelectedExecutionLog(null)
    +              fetchLogs(1)
    +            }}
    +            className={`rounded-md px-3 py-2 text-sm font-medium ${logView === "security" ? "bg-blue-600 text-white" : "bg-gray-200 text-gray-900 dark:bg-gray-700 dark:text-gray-100"}`}
    +          >
    +            Security and Activity
    +          </button>
    +          <button
    +            onClick={() => {
    +              setLogView("execution")
    +              setSelectedLog(null)
    +              setSelectedExecutionLog(null)
    +              fetchExecutionLogs(1)
    +            }}
    +            className={`rounded-md px-3 py-2 text-sm font-medium ${logView === "execution" ? "bg-blue-600 text-white" : "bg-gray-200 text-gray-900 dark:bg-gray-700 dark:text-gray-100"}`}
    +          >
    +            Execution Logs
    +          </button>
    +        </div>
    +        <div className="mt-3 flex flex-wrap gap-2">
    +          {logView === "security" ? (
    +            <>
               <button
                 onClick={() => exportLogs("json")}
                 disabled={exporting}
    @@ -231,11 +312,14 @@ export default function AdminLogsPage() {
               >
                 Export Logs CSV
               </button>
    +            </>
    +          ) : null}
             </div>
             {message ? <p className="mt-2 text-sm text-gray-700 dark:text-gray-200">{message}</p> : null}
           </div>
     
           <div className="rounded-xl border border-gray-200 bg-white shadow-sm dark:border-gray-800 dark:bg-gray-900">
    +        {logView === "security" ? (
             <div className="grid grid-cols-1 gap-3 border-b border-gray-100 p-4 md:grid-cols-6 dark:border-gray-800">
               <input
                 placeholder="Search action, path, IP"
    @@ -293,8 +377,61 @@ export default function AdminLogsPage() {
                 </button>
               </div>
             </div>
    +        ) : (
    +        <div className="grid grid-cols-1 gap-3 border-b border-gray-100 p-4 md:grid-cols-5 dark:border-gray-800">
    +          <input
    +            placeholder="Search execution id, source, IP"
    +            value={executionFilters.search}
    +            onChange={(e) => setExecutionFilters({ ...executionFilters, search: e.target.value })}
    +            className="md:col-span-2 rounded-md border border-gray-300 px-3 py-2 text-sm dark:border-gray-700 dark:bg-gray-800"
    +          />
    +          <select
    +            value={executionFilters.language}
    +            onChange={(e) => setExecutionFilters({ ...executionFilters, language: e.target.value })}
    +            className="rounded-md border border-gray-300 px-3 py-2 text-sm dark:border-gray-700 dark:bg-gray-800"
    +          >
    +            <option value="">All Languages</option>
    +            <option value="python">Python</option>
    +            <option value="javascript">JavaScript</option>
    +            <option value="c">C</option>
    +            <option value="cpp">C++</option>
    +            <option value="java">Java</option>
    +            <option value="go">Go</option>
    +            <option value="rust">Rust</option>
    +          </select>
    +          <select
    +            value={executionFilters.status}
    +            onChange={(e) => setExecutionFilters({ ...executionFilters, status: e.target.value })}
    +            className="rounded-md border border-gray-300 px-3 py-2 text-sm dark:border-gray-700 dark:bg-gray-800"
    +          >
    +            <option value="">All Status</option>
    +            <option value="success">Success</option>
    +            <option value="failed">Failed</option>
    +            <option value="blocked">Blocked</option>
    +          </select>
    +          <div className="flex gap-2">
    +            <button
    +              onClick={() => fetchExecutionLogs(1)}
    +              className="w-full rounded-md bg-blue-600 px-3 py-2 text-sm font-medium text-white hover:bg-blue-700"
    +            >
    +              Apply
    +            </button>
    +            <button
    +              onClick={() => {
    +                const reset = { language: "", status: "", search: "" }
    +                setExecutionFilters(reset)
    +                fetchExecutionLogs(1, reset)
    +              }}
    +              className="w-full rounded-md bg-gray-200 px-3 py-2 text-sm font-medium text-gray-900 hover:bg-gray-300 dark:bg-gray-700 dark:text-gray-100"
    +            >
    +              Clear
    +            </button>
    +          </div>
    +        </div>
    +        )}
     
             <div className="overflow-x-auto">
    +          {logView === "security" ? (
               <table className="min-w-full divide-y divide-gray-200 dark:divide-gray-800">
                 <thead className="bg-gray-50 dark:bg-gray-800/50">
                   <tr>
    @@ -338,23 +475,76 @@ export default function AdminLogsPage() {
                   )}
                 </tbody>
               </table>
    +          ) : (
    +          <table className="min-w-full divide-y divide-gray-200 dark:divide-gray-800">
    +            <thead className="bg-gray-50 dark:bg-gray-800/50">
    +              <tr>
    +                <th className="px-4 py-2 text-left text-xs font-medium uppercase text-gray-500">Time</th>
    +                <th className="px-4 py-2 text-left text-xs font-medium uppercase text-gray-500">Source</th>
    +                <th className="px-4 py-2 text-left text-xs font-medium uppercase text-gray-500">Language</th>
    +                <th className="px-4 py-2 text-left text-xs font-medium uppercase text-gray-500">Execution ID</th>
    +                <th className="px-4 py-2 text-left text-xs font-medium uppercase text-gray-500">Status</th>
    +                <th className="px-4 py-2 text-left text-xs font-medium uppercase text-gray-500">Time (s)</th>
    +              </tr>
    +            </thead>
    +            <tbody className="divide-y divide-gray-100 dark:divide-gray-800">
    +              {loading ? (
    +                <tr>
    +                  <td className="px-4 py-4 text-sm text-gray-600" colSpan={6}>Loading execution logs...</td>
    +                </tr>
    +              ) : executionLogs.length === 0 ? (
    +                <tr>
    +                  <td className="px-4 py-4 text-sm text-gray-500" colSpan={6}>No execution logs found for selected filters.</td>
    +                </tr>
    +              ) : (
    +                executionLogs.map((log) => (
    +                  <tr
    +                    key={log.id}
    +                    onClick={() => setSelectedExecutionLog(log)}
    +                    className="cursor-pointer hover:bg-blue-50 dark:hover:bg-gray-800/60"
    +                    title="Click to view execution request and response details"
    +                  >
    +                    <td className="px-4 py-3 text-xs text-gray-700 dark:text-gray-300">{new Date(log.timestamp).toLocaleString()}</td>
    +                    <td className="px-4 py-3 text-xs text-gray-700 dark:text-gray-300">{log.source || "compiler"}</td>
    +                    <td className="px-4 py-3 text-xs text-gray-700 dark:text-gray-300">{log.language}</td>
    +                    <td className="px-4 py-3 text-xs text-gray-700 dark:text-gray-300">{log.execution_id || "-"}</td>
    +                    <td className="px-4 py-3 text-xs">
    +                      <span className={`rounded px-2 py-1 ${log.status === "success" ? "bg-green-100 text-green-700" : log.status === "blocked" ? "bg-amber-100 text-amber-700" : "bg-red-100 text-red-700"}`}>
    +                        {log.status}
    +                      </span>
    +                    </td>
    +                    <td className="px-4 py-3 text-xs text-gray-700 dark:text-gray-300">{typeof log.execution_time === "number" ? log.execution_time.toFixed(3) : "0.000"}</td>
    +                  </tr>
    +                ))
    +              )}
    +            </tbody>
    +          </table>
    +          )}
             </div>
     
             <div className="flex items-center justify-between border-t border-gray-100 px-4 py-3 text-sm text-gray-600 dark:border-gray-800 dark:text-gray-300">
               <span>
    -            Page {pagination.page} of {pagination.pages} • Total {pagination.total}
    +            {logView === "security"
    +              ? `Page ${pagination.page} of ${pagination.pages} • Total ${pagination.total}`
    +              : `Page ${executionPagination.page} of ${executionPagination.pages} • Total ${executionPagination.total}`}
               </span>
               <div className="flex gap-2">
                 <button
    -              onClick={() => fetchLogs(Math.max(1, pagination.page - 1))}
    -              disabled={pagination.page <= 1}
    +              onClick={() => {
    +                if (logView === "security") fetchLogs(Math.max(1, pagination.page - 1))
    +                else fetchExecutionLogs(Math.max(1, executionPagination.page - 1))
    +              }}
    +              disabled={logView === "security" ? pagination.page <= 1 : executionPagination.page <= 1}
                   className="rounded bg-gray-100 px-3 py-1.5 disabled:opacity-50 dark:bg-gray-800"
                 >
                   Previous
                 </button>
                 <button
    -              onClick={() => fetchLogs(Math.min(pagination.pages, pagination.page + 1))}
    -              disabled={pagination.page >= pagination.pages}
    +              onClick={() => {
    +                if (logView === "security") fetchLogs(Math.min(pagination.pages, pagination.page + 1))
    +                else fetchExecutionLogs(Math.min(executionPagination.pages, executionPagination.page + 1))
    +              }}
    +              disabled={logView === "security" ? pagination.page >= pagination.pages : executionPagination.page >= executionPagination.pages}
                   className="rounded bg-gray-100 px-3 py-1.5 disabled:opacity-50 dark:bg-gray-800"
                 >
                   Next
    @@ -462,6 +652,82 @@ export default function AdminLogsPage() {
               </div>
             </div>
           ) : null}
    +
    +      {selectedExecutionLog ? (
    +        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4">
    +          <div className="w-full max-w-4xl rounded-xl border border-gray-200 bg-white shadow-xl dark:border-gray-800 dark:bg-gray-900">
    +            <div className="flex items-center justify-between border-b border-gray-100 p-4 dark:border-gray-800">
    +              <h2 className="text-lg font-semibold text-gray-900 dark:text-white">Execution Request and Response Details</h2>
    +              <button
    +                onClick={() => setSelectedExecutionLog(null)}
    +                className="rounded-md bg-gray-200 px-3 py-1.5 text-sm text-gray-900 hover:bg-gray-300 dark:bg-gray-700 dark:text-gray-100"
    +              >
    +                Close
    +              </button>
    +            </div>
    +
    +            <div className="max-h-[75vh] space-y-4 overflow-auto p-4">
    +              <div className="grid grid-cols-1 gap-3 md:grid-cols-2">
    +                <div className="rounded-lg border border-gray-200 p-3 dark:border-gray-700">
    +                  <p className="text-xs font-semibold uppercase text-gray-500">Source</p>
    +                  <p className="mt-1 text-sm text-gray-900 dark:text-white">{selectedExecutionLog.source || "compiler"}</p>
    +                </div>
    +                <div className="rounded-lg border border-gray-200 p-3 dark:border-gray-700">
    +                  <p className="text-xs font-semibold uppercase text-gray-500">Language</p>
    +                  <p className="mt-1 text-sm text-gray-900 dark:text-white">{selectedExecutionLog.language}</p>
    +                </div>
    +                <div className="rounded-lg border border-gray-200 p-3 dark:border-gray-700">
    +                  <p className="text-xs font-semibold uppercase text-gray-500">Execution ID</p>
    +                  <p className="mt-1 break-all text-sm text-gray-900 dark:text-white">{selectedExecutionLog.execution_id || "-"}</p>
    +                </div>
    +                <div className="rounded-lg border border-gray-200 p-3 dark:border-gray-700">
    +                  <p className="text-xs font-semibold uppercase text-gray-500">Status</p>
    +                  <p className="mt-1 text-sm text-gray-900 dark:text-white">{selectedExecutionLog.status}</p>
    +                </div>
    +                <div className="rounded-lg border border-gray-200 p-3 dark:border-gray-700">
    +                  <p className="text-xs font-semibold uppercase text-gray-500">Execution Time</p>
    +                  <p className="mt-1 text-sm text-gray-900 dark:text-white">{typeof selectedExecutionLog.execution_time === "number" ? selectedExecutionLog.execution_time.toFixed(3) : "0.000"} s</p>
    +                </div>
    +                <div className="rounded-lg border border-gray-200 p-3 dark:border-gray-700">
    +                  <p className="text-xs font-semibold uppercase text-gray-500">Client</p>
    +                  <p className="mt-1 break-all text-sm text-gray-900 dark:text-white">{selectedExecutionLog.ip || "Unknown"}</p>
    +                  <p className="mt-1 break-all text-xs text-gray-600 dark:text-gray-300">{selectedExecutionLog.user_agent || "Unknown user agent"}</p>
    +                </div>
    +              </div>
    +
    +              <div className="rounded-lg border border-gray-200 p-3 dark:border-gray-700">
    +                <div className="flex items-center justify-between">
    +                  <p className="text-xs font-semibold uppercase text-gray-500">Request Body</p>
    +                  <button
    +                    onClick={() => copyText(safeJson(selectedExecutionLog.request_body ?? { note: "No request body captured for this execution log" }))}
    +                    className="rounded bg-blue-600 px-2 py-1 text-xs text-white hover:bg-blue-700"
    +                  >
    +                    Copy
    +                  </button>
    +                </div>
    +                <pre className="mt-2 max-h-64 overflow-auto whitespace-pre-wrap break-words rounded bg-gray-50 p-3 text-sm leading-6 text-gray-800 dark:bg-gray-800 dark:text-gray-100">
    +{safeJson(selectedExecutionLog.request_body ?? { note: "No request body captured for this execution log" })}
    +                </pre>
    +              </div>
    +
    +              <div className="rounded-lg border border-gray-200 p-3 dark:border-gray-700">
    +                <div className="flex items-center justify-between">
    +                  <p className="text-xs font-semibold uppercase text-gray-500">Response Body</p>
    +                  <button
    +                    onClick={() => copyText(safeJson(selectedExecutionLog.response_body ?? { note: "No response body captured for this execution log" }))}
    +                    className="rounded bg-emerald-600 px-2 py-1 text-xs text-white hover:bg-emerald-700"
    +                  >
    +                    Copy
    +                  </button>
    +                </div>
    +                <pre className="mt-2 max-h-64 overflow-auto whitespace-pre-wrap break-words rounded bg-gray-50 p-3 text-sm leading-6 text-gray-800 dark:bg-gray-800 dark:text-gray-100">
    +{safeJson(selectedExecutionLog.response_body ?? { note: "No response body captured for this execution log" })}
    +                </pre>
    +              </div>
    +            </div>
    +          </div>
    +        </div>
    +      ) : null}
         </div>
       )
     }
    
  • frontend/next-env.d.ts+1 1 modified
    @@ -1,6 +1,6 @@
     /// <reference types="next" />
     /// <reference types="next/image-types/global" />
    -import "./.next/types/routes.d.ts";
    +import "./.next/dev/types/routes.d.ts";
     
     // NOTE: This file should not be edited
     // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
    
  • frontend/.npmignore+10 0 added
    @@ -0,0 +1,10 @@
    +.next
    +node_modules
    +.env*
    +*.log
    +coverage
    +.git
    +.github
    +.vscode
    +.npmrc
    +pnpm-lock.yaml
    
  • frontend/.npmrc+2 0 added
    @@ -0,0 +1,2 @@
    +@th30d4y:registry=https://npm.pkg.github.com
    +//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
    
  • frontend/package.json+24 5 modified
    @@ -1,7 +1,7 @@
     {
    -  "name": "my-v0-project",
    -  "version": "0.1.0",
    -  "private": true,
    +  "name": "openlearnx",
    +  "version": "2.0.3",
    +  "private": false,
       "scripts": {
         "build": "next build",
         "dev": "next dev",
    @@ -81,5 +81,24 @@
         "postcss": "^8.5",
         "tailwindcss": "^3.4.17",
         "typescript": "^5"
    -  }
    -}
    \ No newline at end of file
    +  },
    +  "repository": "https://github.com/th30d4y/OpenLearnX.git",
    +  "publishConfig": {
    +    "registry": "https://registry.npmjs.org"
    +  },
    +  "files": [
    +    "README.md",
    +    "package.json",
    +    "app",
    +    "components",
    +    "context",
    +    "hooks",
    +    "lib",
    +    "public",
    +    "styles",
    +    "next.config.mjs",
    +    "postcss.config.mjs",
    +    "tailwind.config.ts",
    +    "tsconfig.json"
    +  ]
    +}
    
  • frontend/README.md+31 0 added
    @@ -0,0 +1,31 @@
    +# OpenLearnX
    +
    +OpenLearnX is an AI-powered learning platform with adaptive quizzes, coding practice, course tracking, and dashboard analytics.
    +
    +## Install
    +
    +```bash
    +npm i openlearnx
    +```
    +
    +## Project
    +
    +This package contains the OpenLearnX frontend (Next.js).
    +
    +## Quick Start (development)
    +
    +```bash
    +npm install
    +npm run dev
    +```
    +
    +## Build
    +
    +```bash
    +npm run build
    +npm start
    +```
    +
    +## Repository
    +
    +https://github.com/th30d4y/OpenLearnX
    
  • nohup.out+0 0 added
  • start-local-secure.sh+136 0 added
    @@ -0,0 +1,136 @@
    +#!/usr/bin/env bash
    +set -euo pipefail
    +
    +ROOT_DIR="$(cd "$(dirname "$0")" && pwd)"
    +MONGO_DBPATH="${HOME}/mongodata"
    +MONGO_LOG="/tmp/openlearnx_mongod.log"
    +BACKEND_LOG="/tmp/openlearnx_backend.log"
    +FRONTEND_LOG="/tmp/openlearnx_frontend.log"
    +FRONTEND_PID_FILE="/tmp/openlearnx_frontend.pid"
    +VENV_PYTHON="${ROOT_DIR}/venv_openlearnx/bin/python3"
    +
    +cd "$ROOT_DIR"
    +
    +echo "[1/8] Checking prerequisites"
    +command -v mongod >/dev/null 2>&1 || { echo "ERROR: mongod not found"; exit 1; }
    +command -v pnpm >/dev/null 2>&1 || { echo "ERROR: pnpm not found"; exit 1; }
    +command -v docker >/dev/null 2>&1 || { echo "ERROR: docker not found"; exit 1; }
    +[[ -x "$VENV_PYTHON" ]] || { echo "ERROR: Python venv not found at $VENV_PYTHON"; exit 1; }
    +
    +ensure_docker_access() {
    +  if docker info >/dev/null 2>&1; then
    +    return 0
    +  fi
    +
    +  echo "[Docker] Current user cannot access Docker. Attempting automatic fix..."
    +
    +  if ! sudo -n true >/dev/null 2>&1; then
    +    echo "[Docker] sudo authentication required once to configure Docker access."
    +    sudo -v
    +  fi
    +
    +  sudo systemctl enable --now docker
    +
    +  if ! getent group docker >/dev/null 2>&1; then
    +    sudo groupadd docker
    +  fi
    +
    +  sudo usermod -aG docker "$USER"
    +  sudo chgrp docker /var/run/docker.sock || true
    +  sudo chmod 660 /var/run/docker.sock || true
    +
    +  if docker info >/dev/null 2>&1; then
    +    return 0
    +  fi
    +
    +  echo "[Docker] Group refresh required. Testing with sg docker context..."
    +  if sg docker -c 'docker info >/dev/null 2>&1'; then
    +    return 0
    +  fi
    +
    +  echo "ERROR: Docker access is still unavailable after auto-fix."
    +  echo "Run: newgrp docker  (or log out/in) and rerun this script."
    +  exit 1
    +}
    +
    +run_backend() {
    +  if docker info >/dev/null 2>&1; then
    +    nohup "$VENV_PYTHON" backend/main.py >"$BACKEND_LOG" 2>&1 &
    +    sleep 1
    +    pgrep -f "python3 .*backend/main.py" | head -n1 || true
    +    return 0
    +  fi
    +
    +  # Start backend in docker group context when group refresh has not propagated.
    +  sg docker -c "nohup '$VENV_PYTHON' '$ROOT_DIR/backend/main.py' >'$BACKEND_LOG' 2>&1 &"
    +  sleep 1
    +  pgrep -f "python3 .*backend/main.py" | head -n1 || true
    +}
    +
    +echo "[2/8] Ensuring Docker access"
    +ensure_docker_access
    +
    +echo "[3/8] Stopping old local processes"
    +pkill -f "mongod.*--dbpath ${MONGO_DBPATH}" 2>/dev/null || true
    +pkill -f "python3 .*backend/main.py" 2>/dev/null || true
    +pkill -f "pnpm dev" 2>/dev/null || true
    +pkill -f "next dev" 2>/dev/null || true
    +
    +echo "[4/8] Starting MongoDB"
    +mkdir -p "$MONGO_DBPATH"
    +if pgrep -f "mongod.*--dbpath ${MONGO_DBPATH}" >/dev/null 2>&1; then
    +  echo "MongoDB already running for ${MONGO_DBPATH}; reusing existing process"
    +else
    +  set +e
    +  mongod --dbpath "$MONGO_DBPATH" --bind_ip 127.0.0.1 --port 27017 --logpath "$MONGO_LOG" --fork >/tmp/openlearnx_mongod_fork.out 2>&1
    +  mongo_start_code=$?
    +  set -e
    +  if [[ $mongo_start_code -ne 0 ]]; then
    +    echo "WARNING: mongod --fork returned ${mongo_start_code}. Checking if service is still running..."
    +  fi
    +fi
    +MONGO_PID="$(pgrep -f "mongod.*--dbpath ${MONGO_DBPATH}" | head -n1 || true)"
    +if [[ -z "$MONGO_PID" ]]; then
    +  echo "ERROR: MongoDB did not start. Check logs: ${MONGO_LOG} and /tmp/openlearnx_mongod_fork.out"
    +  exit 1
    +fi
    +echo "Mongo PID: ${MONGO_PID:-N/A}"
    +
    +echo "[5/8] Starting backend"
    +BACKEND_PID="$(run_backend)"
    +if [[ -z "$BACKEND_PID" ]]; then
    +  echo "ERROR: Backend did not start. Check log: $BACKEND_LOG"
    +  exit 1
    +fi
    +echo "Backend PID: ${BACKEND_PID:-N/A}"
    +
    +echo "[6/8] Starting frontend"
    +(
    +  cd frontend
    +  nohup pnpm dev >"$FRONTEND_LOG" 2>&1 &
    +  echo "$!" >"$FRONTEND_PID_FILE"
    +)
    +FRONTEND_PID="$(cat "$FRONTEND_PID_FILE")"
    +echo "Frontend PID: ${FRONTEND_PID:-N/A}"
    +
    +echo "[7/8] Waiting for services"
    +backend_code="$(curl -sS -o /tmp/openlearnx_backend_health_body.txt -w "%{http_code}" --retry 30 --retry-all-errors --retry-connrefused --retry-delay 1 http://127.0.0.1:5000/api/health || true)"
    +frontend_code="$(curl -sS -o /tmp/openlearnx_frontend_body.txt -w "%{http_code}" --retry 30 --retry-all-errors --retry-connrefused --retry-delay 1 http://127.0.0.1:3000 || true)"
    +
    +echo "[8/8] Verifying secure compiler execution"
    +compiler_code="$(curl -sS -o /tmp/openlearnx_compiler_smoke.json -w "%{http_code}" -X POST http://127.0.0.1:5000/api/compiler/execute -H "Content-Type: application/json" -d '{"language":"python","code":"print(\"ok\")"}' || true)"
    +
    +echo ""
    +echo "RESULT"
    +echo "  Mongo PID:      ${MONGO_PID:-N/A}"
    +echo "  Backend PID:    ${BACKEND_PID:-N/A}"
    +echo "  Frontend PID:   ${FRONTEND_PID:-N/A}"
    +echo "  Backend health: ${backend_code:-000}  (http://127.0.0.1:5000/api/health)"
    +echo "  Frontend health:${frontend_code:-000}  (http://127.0.0.1:3000)"
    +echo "  Compiler smoke: ${compiler_code:-000}  (/api/compiler/execute)"
    +
    +echo ""
    +echo "Logs:"
    +echo "  MongoDB:  $MONGO_LOG"
    +echo "  Backend:  $BACKEND_LOG"
    +echo "  Frontend: $FRONTEND_LOG"
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.