Example 1: From source to sink

In the following code sample, the main method calls a method, getVulnerableSource, that returns a string. Note that, although the method reads data from a completely unknown file, it never checks the validity of the returned data. The main method then passes this tainted data into writeToVulnerableSink. The writeToVulnerableSink method writes the data out to the file, never checking its validity.

import java.io.*;

public class TestCase_IOT_Static {
  public static void main(String[] args) {
    try {
      writeToVulnerableSink(getVulnerableSource(args[0]));
    } catch (Exception e) {
    }
  }

  public static String getVulnerableSource(String file)
    throws java.io.IOException, java.io.FileNotFoundException {
    FileInputStream fis = new FileInputStream(file);
    byte[] buf = new byte[100];
    fis.read(buf);
    String ret = new String(buf);
    fis.close();
    return ret;
  }

  public static void writeToVulnerableSink(String str)
    throws java.io.FileNotFoundException {
    FileOutputStream fos = new FileOutputStream(str);
    PrintWriter writer = new PrintWriter(fos);
    writer.write(str);
  }
}

The code sample produces this trace:


Trace view

The pane shows the input stack where main calls getVulnerableSource which calls FileInputStream.read - and the output stack where main calls writeToVulnerableSink, which calls PrintWriter.write. The graph displays how the data flows from the read method to the write method, with main joining the two call stacks. The Data Flow section shows the line numbers in the operations in the main method that pass the taint. In this example, both method calls exist on the same line (line 15) within the method (in the sample code above, this translates to line number 7 - in the screen capture, the file includes 8 lines of commenting).