Apache Zeppelin: Cron arbitrary user impersonation with improper privileges
Description
Apache Zeppelin before 0.11.1 has an improper input validation in the cron API, allowing attackers to run notebooks with elevated privileges.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Apache Zeppelin before 0.11.1 has an improper input validation in the cron API, allowing attackers to run notebooks with elevated privileges.
Vulnerability
CVE-2024-31865 is an improper input validation vulnerability in Apache Zeppelin's cron scheduling API. The API fails to enforce proper permission checks when updating cron information, allowing unauthorized modification of notebook schedules [1][2]. The fix, introduced in pull request #4631 and commit 49e2740, adds explicit permission verification before allowing cron updates [1][3].
Exploitation
An attacker can call the updating cron API with invalid or improper privileges, meaning they may lack the required authorization but can still set or modify cron schedules for notebooks [2]. This does not require administrative access; any user who can reach the API endpoint may exploit it. The vulnerability affects Zeppelin versions from 0.8.2 up to (but not including) 0.11.1 [2][4].
Impact
Successful exploitation allows an attacker to schedule notebooks to run with the privileges of another user, effectively impersonating that user [4]. This can lead to arbitrary code execution, data exfiltration, or privilege escalation within the Zeppelin environment, depending on the notebook's content and the privileges of the impersonated user.
Mitigation
Users should upgrade to Apache Zeppelin 0.11.1, which contains the fix [2][3]. No workarounds are documented; upgrading is the recommended action.
- [HOTFIX] Check permission when updating cron information by jongyoul · Pull Request #4631 · apache/zeppelin
- NVD - CVE-2024-31865
- [HOTFIX] Check permission when updating cron information (#4631) · apache/zeppelin@49e2740
- security - CVE-2024-31865: Apache Zeppelin: Cron arbitrary user impersonation with improper privileges
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.apache.zeppelin:zeppelin-serverMaven | >= 0.8.2, < 0.11.1 | 0.11.1 |
Affected products
2Patches
149e2740a1d83[HOTFIX] Check permission when updating cron information (#4631)
4 files changed · +61 −7
zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java+5 −1 modified@@ -596,6 +596,10 @@ public String getShiroPath() { return new File(shiroPath).exists() ? shiroPath : StringUtils.EMPTY; } + public boolean isAuthenticationEnabled() { + return !StringUtils.isBlank(getShiroPath()); + } + public String getInterpreterRemoteRunnerPath() { return getAbsoluteDir(ConfVars.ZEPPELIN_INTERPRETER_REMOTE_RUNNER); } @@ -770,7 +774,7 @@ public String getZeppelinNotebookGitRemoteOrigin() { } public boolean isZeppelinNotebookCronEnable() { - return getBoolean(ConfVars.ZEPPELIN_NOTEBOOK_CRON_ENABLE); + return getBoolean(ConfVars.ZEPPELIN_NOTEBOOK_CRON_ENABLE) && isAuthenticationEnabled(); } public String getZeppelinNotebookCronFolders() {
zeppelin-server/src/main/java/org/apache/zeppelin/service/NotebookService.java+49 −6 modified@@ -879,17 +879,60 @@ public void updateNote(String noteId, return null; } - if (!(Boolean) note.getConfig().get("isZeppelinNotebookCronEnable")) { + if (!zConf.isZeppelinNotebookCronEnable()) { + boolean hasCronSettings = false; if (config.get("cron") != null) { - config.remove("cron"); + LOGGER.warn("cron should be null when cron is disabled"); + hasCronSettings = true; + } + if (config.get("cronExecutingUser") != null) { + LOGGER.warn("cronExecutingUser should be null when cron is disabled"); + hasCronSettings = true; + } + if (config.get("cronExecutingRoles") != null) { + LOGGER.warn("cronExecutingRoles should be null when cron is disabled"); + hasCronSettings = true; + } + if (hasCronSettings) { + callback.onFailure(new IllegalArgumentException("Wrong configs"), context); + return null; + } + } else { + String requestCronUser = (String) config.get("cronExecutingUser"); + Set<String> requestCronRoles = (Set<String>) config.get("cronExecutingRoles"); + + if (!authorizationService.hasRunPermission(Collections.singleton(requestCronUser), note.getId())) { + LOGGER.error("Wrong cronExecutingUser: {}", requestCronUser); + callback.onFailure(new IllegalArgumentException(requestCronUser), context); + return null; + } else { + // This part should be restarted but we need to prepare to notice who can be a cron user in advance + if (!context.getUserAndRoles().contains(requestCronUser)) { + LOGGER.error("Wrong cronExecutingUser: {}", requestCronUser); + callback.onFailure(new IllegalArgumentException(requestCronUser), context); + return null; + } + + if (!context.getUserAndRoles().containsAll(requestCronRoles)) { + LOGGER.error("Wrong cronExecutingRoles: {}", requestCronRoles); + callback.onFailure(new IllegalArgumentException(requestCronRoles.toString()), context); + return null; + } + } + + if (!(Boolean) note.getConfig().get("isZeppelinNotebookCronEnable")) { + if (config.get("cron") != null) { + config.remove("cron"); + } + } + boolean cronUpdated = isCronUpdated(config, note.getConfig()); + if (cronUpdated) { + schedulerService.refreshCron(note.getId()); } } - boolean cronUpdated = isCronUpdated(config, note.getConfig()); + note.setName(name); note.setConfig(config); - if (cronUpdated) { - schedulerService.refreshCron(note.getId()); - } notebook.updateNote(note, context.getAutheInfo()); callback.onSuccess(note, context);
zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java+3 −0 modified@@ -29,6 +29,7 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; @@ -657,6 +658,7 @@ void testRunParagraphWithParams() throws Exception { } } + @Disabled // TODO(ZEPPELIN-5994): Fix and enable this test @Test void testJobs() throws Exception { // create a note and a paragraph @@ -719,6 +721,7 @@ void testJobs() throws Exception { } } + @Disabled // TODO(ZEPPELIN-5994): Fix and enable this test @Test void testCronDisable() throws Exception { String noteId = null;
zeppelin-zengine/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java+4 −0 modified@@ -57,6 +57,7 @@ import java.io.FileWriter; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -111,6 +112,9 @@ public void setUp() throws Exception { schedulerService = new QuartzSchedulerService(conf, notebook); notebook.initNotebook(); notebook.waitForFinishInit(1, TimeUnit.MINUTES); + + // create empty shiro.ini file under confDir + Files.createFile(new File(confDir, "shiro.ini").toPath()); } @Override
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/apache/zeppelin/pull/4631ghsapatchWEB
- github.com/advisories/GHSA-g44m-x5h7-fr5qghsaADVISORY
- lists.apache.org/thread/slm1sf0slwc11f4m4r0nd6ot2rf7w81lghsavendor-advisoryWEB
- nvd.nist.gov/vuln/detail/CVE-2024-31865ghsaADVISORY
- www.openwall.com/lists/oss-security/2024/04/09/9ghsaWEB
- github.com/apache/zeppelin/commit/49e2740a1d83d58d2401ccf175fc91ffebfb0892ghsaWEB
News mentions
0No linked articles in our index yet.