CVE-2023-3431 (Java, published 2023-06-27T15:15Z)
Description: value: Improper Access Control in GitHub repository plantuml/plantuml prior to 1.2023.9.
Severity: nan (CVSS v3 base score: 5.3)
Weakness: CWE-284 \u2014 Improper Access Control
The product does not restrict or incorrectly restricts access to a resource from an unauthorized actor.
Repository: https://github.com/plantuml/plantuml
Files changed:
gradle.properties
src/net/sourceforge/plantuml/OptionFlags.java
src/net/sourceforge/plantuml/preproc/ImportedFiles.java
src/net/sourceforge/plantuml/security/SFile.java
src/net/sourceforge/plantuml/security/SURL.java
src/net/sourceforge/plantuml/security/SecurityProfile.java
src/net/sourceforge/plantuml/security/SecurityUtils.java
src/net/sourceforge/plantuml/tim/stdlib/FileExists.java
src/net/sourceforge/plantuml/tim/stdlib/Getenv.java
src/net/sourceforge/plantuml/tim/stdlib/LoadJson.java
src/net/sourceforge/plantuml/version/LicenseInfo.java
src/net/sourceforge/plantuml/version/PSystemVersion.java
src/net/sourceforge/plantuml/version/Version.java
Commit message: feat: remove legacy ALLOW_INCLUDE use PLANTUML_SECURITY_PROFILE instead
https://github.com/plantuml/plantuml-server/issues/232


Vulnerable code:
version = 1.2023.9beta4
	static public boolean ALLOW_INCLUDE = true;

	static public void setAllowIncludeFalse() {
		ALLOW_INCLUDE = false;
	}
import net.sourceforge.plantuml.OptionFlags;
		if (newCurrentDir == null) {
		}
		if (dir == null || isAbsolute(nameOrPath)) {
		}
		if (filecurrent != null && filecurrent.isOk()) {
		}
				if (file.exists()) {
				}
				if (zipEntry.isOk()) {
				}
		if (isAllowed(file) == false)
	private boolean isAllowed(AFile file) throws IOException {
		// ::comment when __CORE__
		if (OptionFlags.ALLOW_INCLUDE)
			return true;

		if (file != null) {
			final SFile folder = file.getSystemFolder();
			// System.err.println("canonicalPath=" + path + " " + folder + " " +
			// INCLUDE_PATH);
			if (includePath().contains(folder))
				return true;

		}
		// ::done
		return false;
	}
		if (internal == null) {
		}
	private boolean isFileOk() {
	private boolean isUrlOk() {
    // ::remove folder when __HAXE__
	/**
	 * Checks the environment variable and returns true if the variable is used in
	 * security context. In this case, the value should not be displayed in scripts.
	 *
	 * @param name Environment variable to check
	 * @return true, if this is a secret variable
	 */
	public static boolean isSecurityEnv(String name) {
		return name != null && name.toLowerCase().startsWith("plantuml.security.");
	}
import net.sourceforge.plantuml.OptionFlags;
		if (OptionFlags.ALLOW_INCLUDE == false)
			// ::done
			return TValue.fromBoolean(false);
		// ::comment when __CORE__

		return TValue.fromBoolean(fileExists(path));
	}
	private boolean fileExists(String path) {
		final SFile f = new SFile(path);
		return f.exists();
import net.sourceforge.plantuml.OptionFlags;
		if (OptionFlags.ALLOW_INCLUDE == false)
			// ::done
			return TValue.fromString("");
		// ::comment when __CORE__

		final String name = values.get(0).toString();
		final String value = getenv(name);
		if (SecurityUtils.isSecurityEnv(name))
			if (url == null)
				throw EaterException.located("load JSON: Invalid URL " + path);
			byteData = url.getBytes();
				throw EaterException.located("load JSON: Cannot read file " + path + ". " + e.getMessage());
		if (OptionFlags.ALLOW_INCLUDE == false)
			return cache;
		if (OptionFlags.ALLOW_INCLUDE) {
			if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE)
				strings.add("Loaded from " + Version.getJarPath());
	private static final String version = "1.2023.9beta4";

Fixed code:
version = 1.2023.9beta5
//	static public boolean ALLOW_INCLUDE = true;
//
//	static public void setAllowIncludeFalse() {
//		ALLOW_INCLUDE = false;
//	}
		if (newCurrentDir == null) 
		
		if (dir == null || isAbsolute(nameOrPath)) 
		
		if (filecurrent != null && filecurrent.isOk()) 
		
				if (file.exists()) 
				
				if (zipEntry.isOk()) 
				
		// if (isAllowed(file) == false)
		if (file == null || file.getUnderlyingFile().isFileOk() == false)
//	private boolean isAllowed(AFile file) throws IOException {
//		// ::comment when __CORE__
//		if (file != null) {
//			final SFile folder = file.getSystemFolder();
//			// System.err.println("canonicalPath=" + path + " " + folder + " " +
//			// INCLUDE_PATH);
//			if (includePath().contains(folder) && folder.isFileOk())
//				return true;
//
//		}
//		// ::done
//		return false;
//	}
		if (internal == null)

	public boolean isFileOk() {
	public boolean isUrlOk() {
	// ::remove folder when __HAXE__
	public boolean canWeReadThisEnvironmentVariable(String name) {
		if (name == null)
			return false;

		if (this == UNSECURE)
			return true;
		
		if (name.toLowerCase().startsWith("plantuml"))
			return true;
		
		return true;
	}

//	/**
//	 * Checks the environment variable and returns true if the variable is used in
//	 * security context. In this case, the value should not be displayed in scripts.
//	 *
//	 * @param name Environment variable to check
//	 * @return true, if this is a secret variable
//	 */
//	public static boolean isSecurityEnv(String name) {
//		return name != null && name.toLowerCase().startsWith("plantuml.security.");
//	}
		return TValue.fromBoolean(new SFile(path).exists());
		// ::uncomment when __CORE__
		// return TValue.fromBoolean(false);
		// ::done

		final String value = getenv(values.get(0).toString());

		// ::uncomment when __CORE__
		// return TValue.fromString("");
		// ::done
		if (SecurityUtils.getSecurityProfile().canWeReadThisEnvironmentVariable(name) == false)
		
			if (url != null)
				byteData = url.getBytes();
//		if (OptionFlags.ALLOW_INCLUDE == false)
//			return cache;
		if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE) {
			strings.add("Loaded from " + Version.getJarPath());
	private static final String version = "1.2023.9beta5";