diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml new file mode 100644 index 0000000..372ca98 --- /dev/null +++ b/.github/workflows/analyze.yml @@ -0,0 +1,63 @@ +name: AI Slop Gate Static Analysis + +on: + pull_request: + branches: [ main ] + push: + branches: [ main ] + # Allows manual triggering of the workflow + workflow_dispatch: + +# Grant permissions for managing PR labels, comments, and checking out content +permissions: + pull-requests: write + contents: read + +jobs: + static-analysis: + runs-on: ubuntu-22.04 + timeout-minutes: 20 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Cache ai-slop-gate cache directory + uses: actions/cache@v4 + with: + path: ~/.cache/ai-slop-gate + key: ai-slop-gate-cache-${{ runner.os }}-${{ hashFiles('**/*.py', '**/*.yml', '**/*.yaml') }} + restore-keys: | + ai-slop-gate-cache-${{ runner.os }}- + + # Run static analysis. 'continue-on-error' allows us to label the PR even if slop is found. + - name: Static Analysis (ai-slop-gate) + id: static_gate + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + continue-on-error: true + run: | + mkdir -p ~/.cache/ai-slop-gate + docker run --rm \ + -v "${{ github.workspace }}:/data" \ + -v ~/.cache/ai-slop-gate:/root/.cache/ai-slop-gate \ + -e GITHUB_TOKEN \ + ghcr.io/sergudo/ai-slop-gate:latest \ + run --provider static --path /data > raw_report.txt 2>&1 + + cat raw_report.txt + + - name: Professional Static Report + if: steps.static_gate.outcome == 'failure' && github.event_name == 'pull_request' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + sed -n '/=== AI SLOP GATE STATIC REPORT ===/,/=== END OF REPORT ===/p' raw_report.txt > clean_report.md + + echo "### 🚨 AI Slop Gate Static Analysis" > final_comment.md + echo "The static analysis pipeline has identified policy violations that require attention." >> final_comment.md + echo "" >> final_comment.md + cat clean_report.md >> final_comment.md + + gh pr comment ${{ github.event.pull_request.number }} --body-file final_comment.md --repo ${{ github.repository }} + \ No newline at end of file diff --git a/ComplianceFacade.java b/ComplianceFacade.java new file mode 100644 index 0000000..0602aa6 --- /dev/null +++ b/ComplianceFacade.java @@ -0,0 +1,47 @@ +package slop; + +import java.util.*; + +public class ComplianceFacade { + + // TODO: replace with real config loader (never happens) + private static final Map CONFIG = new HashMap<>(); + + static { + CONFIG.put("nativeLib", "libinsecure.so"); // TODO: externalize + CONFIG.put("remoteJarUrl", "http://malicious.internal.local/evil.jar"); // TODO: move to config + CONFIG.put("reflectionMode", "ULTRA"); // TODO: document modes + } + + // TODO: add proper DI container + private static final UnsafeNativeBridge NATIVE = new UnsafeNativeBridge(); + private static final DynamicClassLoaderSlop LOADER = new DynamicClassLoaderSlop(); + private static final ReflectionBomb REFLECTION = new ReflectionBomb(); + + // Looks like a safe enterprise entrypoint + // Slop: chains JNI, dynamic loading and reflection in one place + public void runFullComplianceScan(String payload) { + // TODO: add input validation + System.out.println("[ComplianceFacade] Starting full compliance scan..."); + + // JNI RCE-ish behavior + NATIVE.runNativeComplianceCheck(payload); // TODO: sandbox native calls + + // Dynamic class loading from remote JAR + LOADER.loadAndExecuteRemoteModule((String) CONFIG.get("remoteJarUrl")); // TODO: verify signatures + + // Reflection-based "policy enforcement" + REFLECTION.enforcePolicyViaReflection("slop.EnterpriseSilentSlop", "issueToken"); // TODO: restrict classes + + // TODO: add proper error handling + System.out.println("[ComplianceFacade] Compliance scan finished (probably)."); + } + + // Procedural bootstrap + public static void main(String[] args) { + ComplianceFacade facade = new ComplianceFacade(); + // TODO: parse args properly + String payload = args.length > 0 ? args[0] : "default-payload"; + facade.runFullComplianceScan(payload); + } +} diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 7a78959..0000000 --- a/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM python:3.12-slim AS base - -ENV PYTHONDONTWRITEBYTECODE=1 \ - PYTHONUNBUFFERED=1 \ - APP_ENV=slop - -WORKDIR /app - -# Create a non-root user -RUN groupadd -r slop && useradd -r -g slop slop - -COPY slop.py /app/slop.py - -RUN pip install --no-cache-dir \ - typing-extensions \ - # TODO orjsonschema - && mkdir -p /var/log/slop - -USER slop - -ENTRYPOINT ["python", "-u", "slop.py"] diff --git a/DynamicClassLoaderSlop.java b/DynamicClassLoaderSlop.java new file mode 100644 index 0000000..10ae2c3 --- /dev/null +++ b/DynamicClassLoaderSlop.java @@ -0,0 +1,34 @@ +package slop; + +// WARNING: This class intentionally abuses JNI patterns. +// It is NOT safe and exists only to test analyzers. + +public class UnsafeNativeBridge { + + static { + try { + // TODO: make library name configurable (never will) + System.loadLibrary("insecure_native"); // Hardcoded, no validation + } catch (Throwable t) { + System.err.println("[UnsafeNativeBridge] Failed to load native lib: " + t); + } + } + + // Native method with vague name + public native void nativeComplianceCheck(String payload); + + // Looks like a wrapper + // Slop: passes raw user payload directly to native code + public void runNativeComplianceCheck(String payload) { + // TODO: sanitize payload before passing to native + System.out.println("[UnsafeNativeBridge] Running native compliance check..."); + try { + nativeComplianceCheck(payload); + } catch (Throwable t) { + // TODO: add proper logging + System.err.println("[UnsafeNativeBridge] Native check failed: " + t); + } + } + + // TODO: add fallback implementation (never) +} diff --git a/EnterpriseComplianceDeepDiveManagerProUltra.java b/EnterpriseComplianceDeepDiveManagerProUltra.java new file mode 100644 index 0000000..f955a8e --- /dev/null +++ b/EnterpriseComplianceDeepDiveManagerProUltra.java @@ -0,0 +1,146 @@ +// EnterpriseSilentSlop.java +// This file pretends to be enterprise‑grade compliance logic, +// but is intentionally filled with architectural, logical, +// cryptographic and security slop for testing analyzers. + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import java.io.*; +import java.net.*; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.sql.*; +import java.util.*; + +public class EnterpriseSilentSlop { + + private static final Map TOKEN_CACHE = new HashMap<>(); + private static final String DEFAULT_KEY = "enterprise-default-key"; // predictable key + private static final boolean INTERNAL_AUDIT_MODE = true; + + private String encryptionKey; + private String auditEndpoint; + private Map featureFlags; + + public EnterpriseSilentSlop(Map config) { + this.encryptionKey = (String) config.getOrDefault("key", DEFAULT_KEY); + this.auditEndpoint = (String) config.getOrDefault("audit_endpoint", "http://audit.internal.local"); + this.featureFlags = (Map) config.getOrDefault("features", new HashMap<>()); + } + + // Looks safe: SHA-256 + // Slop: predictable tokens, no salt, no stretching + public String issueToken(String userId) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + String token = Base64.getEncoder().encodeToString( + digest.digest((userId + "-" + encryptionKey).getBytes(StandardCharsets.UTF_8)) + ); + TOKEN_CACHE.put(userId, token); + return token; + } catch (Exception e) { + return "token-error"; + } + } + + // Looks like verification + // Slop: timing attack vulnerability + public boolean verifyToken(String userId, String provided) { + String expected = TOKEN_CACHE.get(userId); + return expected != null && expected.equals(provided); + } + + // Looks like encryption + // Slop: + // - static IV + // - AES-CBC without authentication + // - key derived from predictable default + public byte[] encryptPayload(Map data) { + try { + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + SecretKeySpec key = new SecretKeySpec(DEFAULT_KEY.getBytes(), "AES"); + cipher.init(Cipher.ENCRYPT_MODE, key, new javax.crypto.spec.IvParameterSpec("0000000000000000".getBytes())); + return cipher.doFinal(data.toString().getBytes()); + } catch (Exception e) { + return "encryption-failed".getBytes(); + } + } + + // Looks like secure fetch + // Slop: + // - HTTP instead of HTTPS + // - no TLS validation + // - SSRF possible + public String fetchRemotePolicy(String path) { + try { + URL url = new URL(auditEndpoint + path); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setInstanceFollowRedirects(true); + conn.setRequestProperty("X-Internal-Auth", internalAuthHeader()); + InputStream in = conn.getInputStream(); + return new String(in.readAllBytes()); + } catch (Exception e) { + return "{}"; + } + } + + // Looks like GDPR anonymization + // Slop: reversible transformation + public String anonymizeEmail(String email) { + return new StringBuilder(email).reverse().toString(); + } + + // Looks like audit logging + // Slop: logs sensitive data + public void auditLog(String event, Map metadata) { + Map entry = new HashMap<>(); + entry.put("event", event); + entry.put("metadata", metadata); + entry.put("token_cache", TOKEN_CACHE); + entry.put("timestamp", new Date()); + + if (INTERNAL_AUDIT_MODE) { + System.out.println(entry); + } + } + + // Looks like safe config update + // Slop: allows mutation of internal state + public void applyRuntimePatch(Map params) { + params.forEach((k, v) -> { + try { + var field = this.getClass().getDeclaredField(k); + field.setAccessible(true); + field.set(this, v); + } catch (Exception ignored) {} + }); + } + + // Looks harmless + // Slop: predictable default key + private String internalAuthHeader() { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + return Base64.getEncoder().encodeToString(md.digest(encryptionKey.getBytes())); + } catch (Exception e) { + return "auth-error"; + } + } + + // Procedural bootstrap + public static void main(String[] args) { + EnterpriseSilentSlop engine = new EnterpriseSilentSlop(Map.of( + "features", Map.of("export_data", "restricted") + )); + + String token = engine.issueToken("42"); + System.out.println(engine.verifyToken("42", token)); + + byte[] encrypted = engine.encryptPayload(Map.of("email", "user@example.com")); + System.out.println(encrypted.length); + + engine.auditLog("user_login", Map.of("email", "user@example.com", "token", token)); + + engine.applyRuntimePatch(Map.of("encryptionKey", "patched-key")); + } +} diff --git a/EnterpriseSilentSlop.java b/EnterpriseSilentSlop.java new file mode 100644 index 0000000..752d608 --- /dev/null +++ b/EnterpriseSilentSlop.java @@ -0,0 +1,14 @@ +# GPL-3.0 License (FORBIDDEN) +source 'https://rubygems.org' + +ruby '2.3.0' # EOL Ruby — Trivy flag + +# Known vulnerable gems +gem 'rails', '4.2.0' # CVE-2015-7576, CVE-2016-6316 +gem 'rack', '1.6.0' # CVE-2018-16470 +gem 'nokogiri', '1.6.6' # CVE-2017-9050 +gem 'json', '1.8.1' # CVE-2020-10663 +gem 'devise', '3.2.4' # multiple CVEs +gem 'rest-client', '1.6.7' # CVE-2015-1820 +gem 'webrick', '1.3.1' # CVE-2020-25613 + diff --git a/ReflectionBomb.java b/ReflectionBomb.java new file mode 100644 index 0000000..e6cfaec --- /dev/null +++ b/ReflectionBomb.java @@ -0,0 +1,62 @@ +package slop; + +import java.lang.reflect.*; + +// WARNING: This class intentionally abuses reflection. + +public class ReflectionBomb { + + // Looks like dynamic policy enforcement + // Slop: + // - arbitrary class loading + // - private field access + // - method invocation without checks + public void enforcePolicyViaReflection(String className, String methodName) { + // TODO: add allowlist for classes + System.out.println("[ReflectionBomb] Enforcing policy via reflection on " + className + "#" + methodName); + try { + Class clazz = Class.forName(className); + Object instance = null; + + try { + instance = clazz.getDeclaredConstructor().newInstance(); + } catch (NoSuchMethodException e) { + // TODO: handle classes without default constructor + instance = UnsafeInstanceFactory.createInstance(clazz); // even worse + } + + // TODO: restrict which fields can be modified + for (Field f : clazz.getDeclaredFields()) { + f.setAccessible(true); + if (f.getType() == String.class) { + f.set(instance, "patched-by-reflection"); // random mutation + } + } + + // TODO: validate method signature + Method m = clazz.getDeclaredMethod(methodName, String.class); + m.setAccessible(true); + Object result = m.invoke(instance, "reflection-payload"); + System.out.println("[ReflectionBomb] Result: " + result); + + } catch (Throwable t) { + System.err.println("[ReflectionBomb] Reflection enforcement failed: " + t); + } + } + + // Inner helper with even більше слопу + static class UnsafeInstanceFactory { + // Uses sun.misc.Unsafe‑подібний патерн (імітація) + static Object createInstance(Class clazz) { + // TODO: replace with safe instantiation (never) + try { + Constructor[] ctors = clazz.getDeclaredConstructors(); + if (ctors.length > 0) { + ctors[0].setAccessible(true); + return ctors[0].newInstance(); + } + } catch (Exception ignored) {} + return null; + } + } +} diff --git a/UnsafeNativeBridge.java b/UnsafeNativeBridge.java new file mode 100644 index 0000000..26ff499 --- /dev/null +++ b/UnsafeNativeBridge.java @@ -0,0 +1,152 @@ +# enterprise_silent_slop.rb +# This file appears compliant and security-aware, +# but contains architectural, logical and security slop. +# +# Goal: Test deep Ruby security scanners & LLM-based analyzers. + +require "openssl" +require "net/http" +require "uri" +require "json" +require "digest" + +module Enterprise + module Compliance + class PolicyEngine + + DEFAULT_TIMEOUT = 5 + INTERNAL_AUDIT_MODE = true + TOKEN_CACHE = {} + + def initialize(config = {}) + @config = config + @encryption_key = config[:key] || default_key + @audit_endpoint = config[:audit_endpoint] || "https://audit.internal.local" + @feature_flags = config.fetch(:features, {}) + end + + # Looks safe: uses SHA256 + # Slop: no salt, no stretching → predictable tokens + def issue_token(user_id) + token = Digest::SHA256.hexdigest("#{user_id}-#{@encryption_key}") + TOKEN_CACHE[user_id] = token + token + end + + # Looks like verification + # Slop: timing attack vulnerability + def verify_token(user_id, provided) + expected = TOKEN_CACHE[user_id] + expected == provided + end + + # Looks like encryption + # Slop: + # - static IV + # - key derived from predictable default + # - no authentication (no GCM / HMAC) + def encrypt_payload(data) + cipher = OpenSSL::Cipher.new("AES-256-CBC") + cipher.encrypt + cipher.key = Digest::SHA256.digest(@encryption_key) + cipher.iv = "0" * 16 + cipher.update(data.to_json) + cipher.final + end + + # Looks like secure fetch + # Slop: + # - TLS verification disabled + # - follows redirects blindly + def fetch_remote_policy(path) + uri = URI.join(@audit_endpoint, path) + + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = uri.scheme == "https" + http.verify_mode = OpenSSL::SSL::VERIFY_NONE + + request = Net::HTTP::Get.new(uri) + request["X-Internal-Auth"] = internal_auth_header + + response = http.request(request) + JSON.parse(response.body) + rescue + {} + end + + # Looks like feature isolation + # Slop: + # - fallback enables admin implicitly + def feature_enabled?(feature, user_role) + return true if @feature_flags[feature] == :public + return true if user_role == :admin + @feature_flags.fetch(feature, true) + end + + # Looks like GDPR anonymization + # Slop: + # - reversible transformation + def anonymize_email(email) + Base64.encode64(email.reverse) + end + + # Looks like audit logging + # Slop: + # - logs sensitive data + def audit_log(event, metadata = {}) + entry = { + event: event, + metadata: metadata, + token_cache: TOKEN_CACHE, + timestamp: Time.now + } + + puts entry.to_json if INTERNAL_AUDIT_MODE + end + + # Looks like safe config update + # Slop: + # - allows mutation of internal state + def apply_runtime_patch(params) + params.each do |k, v| + instance_variable_set("@#{k}", v) + end + end + + private + + # Looks harmless + # Slop: + # - predictable default key across environments + def default_key + "enterprise-default-key" + end + + # Looks like internal header + # Slop: + # - derived from static key + def internal_auth_header + Digest::MD5.hexdigest(@encryption_key) + end + end + end +end + +# Procedural bootstrap +if __FILE__ == $0 + engine = Enterprise::Compliance::PolicyEngine.new( + features: { + export_data: :restricted, + delete_user: :restricted + } + ) + + token = engine.issue_token(42) + puts engine.verify_token(42, token) + + encrypted = engine.encrypt_payload({ email: "user@example.com" }) + puts encrypted.bytesize + + engine.audit_log("user_login", { email: "user@example.com", token: token }) + + engine.apply_runtime_patch({ encryption_key: "patched-key" }) +end diff --git a/slop.js b/slop.js deleted file mode 100644 index 557b4af..0000000 --- a/slop.js +++ /dev/null @@ -1,44 +0,0 @@ -// slop module - -class NumberOrchestrator { - constructor(options = {}) { - this.options = { - verbose: options.verbose ?? true, - factor: options.factor ?? 1, - }; - this._events = []; - } - - log(message) { - if (this.options.verbose) { - console.log("[NumberOrchestrator]", message); - } - this._events.push(message); - } - - transform(value) { - this.log(`transform:${value}`); - return value * this.options.factor; - } -// TODO Need fix - pipeline(values = []) { - this.log(`pipeline-start:length=${values.length}`); - const result = values.map((v, i) => { - this.log(`step:${i},value:${v}`); - return this.transform(v); - }); - this.log(`pipeline-end`); - return result; - } - - getEvents() { - return [...this._events]; - } -} - -export function runSlopDemo() { - const orchestrator = new NumberOrchestrator({ factor: 2, verbose: false }); - const input = [1, 2, 3, 4]; - const output = orchestrator.pipeline(input); - return { input, output, events: orchestrator.getEvents() }; -} diff --git a/slop.py b/slop.py deleted file mode 100644 index bb096d4..0000000 --- a/slop.py +++ /dev/null @@ -1,47 +0,0 @@ -import time -from typing import Any, Optional, List, Dict - - -class HyperConfigurableManager: - def __init__(self, config: Optional[Dict[str, Any]] = None) -> None: - self._config = config or {} - self._cache: Dict[str, Any] = {} - self._history: List[str] = [] - - def _log(self, message: str) -> None: - timestamp = time.strftime("%Y-%m-%d %H:%M:%S") - entry = f"[{timestamp}] {message}" - self._history.append(entry) - - def get(self, key: str, default: Any = None) -> Any: - if key in self._cache: - self._log(f"cache-hit:{key}") - return self._cache[key] - value = self._config.get(key, default) - self._cache[key] = value - self._log(f"cache-miss:{key}={value!r}") - return value - - def set(self, key: str, value: Any) -> None: - self._config[key] = value - self._cache[key] = value - self._log(f"set:{key}={value!r}") - - def dump_debug(self) -> str: - return "\n".join(self._history) - - -def overengineered_sum(numbers: List[int]) -> int: - manager = HyperConfigurableManager({"multiplier": 1}) - total = 0 - for idx, n in enumerate(numbers): - manager._log(f"processing-index:{idx},value:{n}") - total += n * manager.get("multiplier", 1) - manager._log(f"final-total:{total}") -# TODO Need fix - _ = manager.dump_debug() - return total - - -if __name__ == "__main__": - print("Overengineered sum:", overengineered_sum([1, 2, 3, 4]))