CVE-2013-2035 (Java, published 2013-08-28T23:55Z)
Description: value: Race condition in hawtjni-runtime/src/main/java/org/fusesource/hawtjni/runtime/Library.java in HawtJNI before 1.8, when a custom library path is not specified, allows local users to execute arbitrary Java code by overwriting a temporary JAR file with a predictable name in /tmp.
Severity: MEDIUM (CVSS v3 base score: )
Weakness: CWE-94 \u2014 Improper Control of Generation of Code ('Code Injection')
The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.
Repository: https://github.com/fusesource/hawtjni
Files changed:
hawtjni-runtime/src/main/java/org/fusesource/hawtjni/runtime/Library.java
Commit message: Simplify shared lib extraction.

Vulnerable code:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
            
            
                File target = file(customPath, map(libName));
                if( extract(errors, resource, target) ) {
            File target = file(customPath, map(libName));
            if( extract(errors, resource, target) ) {
    private boolean extract(ArrayList<String> errors, URL source, File target) {
        FileOutputStream os = null;
        InputStream is = null;
        boolean extracting = false;
            if (!target.exists() || isStale(source, target) ) {
                    extracting = true;
                    os.close();
                    is.close();
            try {
                if (os != null)
                    os.close();
            } catch (IOException e1) {
            }
            try {
                if (is != null)
                    is.close();
            } catch (IOException e1) {
            }
            if (extracting && target.exists())
            return false;
        return true;
    private boolean isStale(URL source, File target) {
        
        if( source.getProtocol().equals("jar") ) {
            // unwrap the jar protocol...
                String parts[] = source.getFile().split(Pattern.quote("!"));
                source = new URL(parts[0]);
            } catch (MalformedURLException e) {
                return false;
            }
        }
        
        File sourceFile=null;
        if( source.getProtocol().equals("file") ) {
            sourceFile = new File(source.getFile());
        }
        if( sourceFile!=null && sourceFile.exists() ) {
            if( sourceFile.lastModified() > target.lastModified() ) {
                return true;
        return false;

Fixed code:
import java.io.*;
import java.util.Random;

            String []libNameParts = map(libName).split("\\.");
            String prefix = libNameParts[0]+"-";
            String suffix = "."+libNameParts[1];

                File target = extract(errors, resource, prefix, suffix, file(customPath));
                if( target!=null ) {
            File target = extract(errors, resource, prefix, suffix, file(customPath));
            if( target!=null ) {
    private File extract(ArrayList<String> errors, URL source, String prefix, String suffix, File directory) {
        File target = null;
            FileOutputStream os = null;
            InputStream is = null;
            try {
                target = File.createTempFile(prefix, suffix, directory);
                target.deleteOnExit();
                return target;
            } finally {
                close(os);
                close(is);
            if( target!=null ) {
            }
        return null;
    static private void close(Closeable file) {
        if(file!=null) {
                file.close();
            } catch (Exception ignore) {