Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added missing "GOOD" and "BAD" to some examples #18645

Merged
merged 3 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response)

StringBuilder sqlQueryBuilder = new StringBuilder();
sqlQueryBuilder.append("SELECT * FROM user WHERE user_id='");
// BAD: a request parameter is concatenated directly into a SQL query
sqlQueryBuilder.append(request.getParameter("user_id"));
sqlQueryBuilder.append("'");

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
public class PartialPathTraversalBad {
public void example(File dir, File parent) throws IOException {
if (!dir.getCanonicalPath().startsWith(parent.getCanonicalPath())) {
if (!dir.getCanonicalPath().startsWith(parent.getCanonicalPath())) { // BAD: dir.getCanonicalPath() not slash-terminated
fabienpe marked this conversation as resolved.
Show resolved Hide resolved
throw new IOException("Path traversal attempt: " + dir.getCanonicalPath());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

public class PartialPathTraversalGood {
public void example(File dir, File parent) throws IOException {
if (!dir.toPath().normalize().startsWith(parent.toPath())) {
if (!dir.toPath().normalize().startsWith(parent.toPath())) { // GOOD: Check if dir.Path() is normalised
throw new IOException("Path traversal attempt: " + dir.getCanonicalPath());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ public String studentEmail(String studentName) {
webview.loadData("", "text/html", null);

String name = "Robert'; DROP TABLE students; --";
webview.loadUrl("javascript:alert(exposedObject.studentEmail(\""+ name +"\"))");
webview.loadUrl("javascript:alert(exposedObject.studentEmail(\""+ name +"\"))"); // BAD: Untrusted input loaded into WebView
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
WebSettings settings = webview.getSettings();
settings.setJavaScriptEnabled(false);
settings.setJavaScriptEnabled(false); // GOOD: webview has JavaScript disabled
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
WebSettings settings = webview.getSettings();
settings.setJavaScriptEnabled(true);
settings.setJavaScriptEnabled(true); // BAD: webview has JavaScript enabled
8 changes: 4 additions & 4 deletions java/ql/src/Security/CWE/CWE-094/GroovyInjectionBad.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,26 @@ public class GroovyInjection {
void injectionViaClassLoader(HttpServletRequest request) {
String script = request.getParameter("script");
final GroovyClassLoader classLoader = new GroovyClassLoader();
Class groovy = classLoader.parseClass(script);
Class groovy = classLoader.parseClass(script); // BAD: Groovy code injection
GroovyObject groovyObj = (GroovyObject) groovy.newInstance();
}

void injectionViaEval(HttpServletRequest request) {
String script = request.getParameter("script");
Eval.me(script);
Eval.me(script); // BAD: Groovy code injection
}

void injectionViaGroovyShell(HttpServletRequest request) {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
shell.evaluate(script);
shell.evaluate(script); // BAD: Groovy code injection
}

void injectionViaGroovyShellGroovyCodeSource(HttpServletRequest request) {
GroovyShell shell = new GroovyShell();
String script = request.getParameter("script");
GroovyCodeSource gcs = new GroovyCodeSource(script, "test", "Test");
shell.evaluate(gcs);
shell.evaluate(gcs); // BAD: Groovy code injection
}
}

2 changes: 1 addition & 1 deletion java/ql/src/Security/CWE/CWE-094/InstallApkWithFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@
File file = new File(Environment.getExternalStorageDirectory(), "myapp.apk");
Intent intent = new Intent(Intent.ACTION_VIEW);
/* Set the mimetype to APK */
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); // BAD: The file may be altered by another app

startActivity(intent);
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

/* Expose temporary file with FileProvider */
File toInstall = new File(this.getFilesDir(), tempFilename);
Uri applicationUri = FileProvider.getUriForFile(this, "com.example.apkprovider", toInstall);
Uri applicationUri = FileProvider.getUriForFile(this, "com.example.apkprovider", toInstall); // GOOD: The file is protected by FileProvider

/* Create Intent and set data to APK file. */
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// GOOD: Package installed using PackageInstaller
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
Expand Down
2 changes: 1 addition & 1 deletion java/ql/src/Security/CWE/CWE-094/SSTIBad.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ public void bad(HttpServletRequest request) {

StringWriter w = new StringWriter();
// evaluate( Context context, Writer out, String logTag, String instring )
Velocity.evaluate(context, w, "mystring", code);
Velocity.evaluate(context, w, "mystring", code); // BAD: code is controlled by the user
}
}
2 changes: 1 addition & 1 deletion java/ql/src/Security/CWE/CWE-094/SSTIGood.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public void good(HttpServletRequest request) {

String s = "We are using $project $name to render this.";
StringWriter w = new StringWriter();
Velocity.evaluate(context, w, "mystring", s);
Velocity.evaluate(context, w, "mystring", s); // GOOD: s is a constant string
System.out.println(" string : " + w);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ public void evaluate(Socket socket) throws IOException {

JexlSandbox onlyMath = new JexlSandbox(false);
onlyMath.white("java.lang.Math");
JexlEngine jexl = new JexlBuilder().sandbox(onlyMath).create();
JexlEngine jexl = new JexlBuilder().sandbox(onlyMath).create(); // GOOD: using a sandbox

String input = reader.readLine();
JexlExpression expression = jexl.createExpression(input);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public void evaluate(Socket socket) throws IOException {
JexlEngine jexl = new JexlBuilder().uberspect(sandbox).create();

String input = reader.readLine();
JexlExpression expression = jexl.createExpression(input);
JexlExpression expression = jexl.createExpression(input); // GOOD: jexl uses a sandbox
JexlContext context = new MapContext();
expression.evaluate(context);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ public Object evaluate(Socket socket) throws IOException {

String string = reader.readLine();
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(string);
Expression expression = parser.parseExpression(string); // AVOID: string is controlled by the user
SimpleEvaluationContext context
= SimpleEvaluationContext.forReadWriteDataBinding().build();
return expression.getValue(context);
return expression.getValue(context); // OK: Untrusted expressions are evaluated in a restricted context
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ public void evaluate(Socket socket) throws IOException {

String input = reader.readLine();
JexlEngine jexl = new JexlBuilder().create();
JexlExpression expression = jexl.createExpression(input);
JexlExpression expression = jexl.createExpression(input); // BAD: input is controlled by the user
JexlContext context = new MapContext();
expression.evaluate(context);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ public Object evaluate(Socket socket) throws IOException {

String string = reader.readLine();
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(string);
Expression expression = parser.parseExpression(string); // BAD: string is controlled by the user
return expression.getValue();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
byte[] iv = new byte[16]; // all zeroes
byte[] iv = new byte[16]; // BAD: all zeroes
GCMParameterSpec params = new GCMParameterSpec(128, iv);
Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, key, params);
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
byte[] iv = new byte[16];
SecureRandom random = SecureRandom.getInstanceStrong();
random.nextBytes(iv);
random.nextBytes(iv); // GOOD: random initialization vector
GCMParameterSpec params = new GCMParameterSpec(128, iv);
Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, key, params);
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
TextView pwView = getViewById(R.id.pw_text);
pwView.setText("Your password is: " + password);
pwView.setText("Your password is: " + password); // BAD: password is shown immediately
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
Button showButton = findViewById(R.id.show_pw_button);
showButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
pwView.setVisibility(View.VISIBLE);
pwView.setVisibility(View.VISIBLE); // GOOD: password is only shown when the user clicks the button
}
});
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
WebSettings settings = webview.getSettings();

// GOOD: WebView is configured to disallow content access
settings.setAllowContentAccess(false);
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
WebSettings settings = webview.getSettings();

// BAD: WebView is configured to allow content access
settings.setAllowContentAccess(true);
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
WebSettings settings = view.getSettings();

// GOOD: WebView is configured to disallow file access
settings.setAllowFileAccess(false);
settings.setAllowFileAccessFromURLs(false);
settings.setAllowUniversalAccessFromURLs(false);
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
WebSettings settings = view.getSettings();

// BAD: WebView is configured to allow file access
settings.setAllowFileAccess(true);
settings.setAllowFileAccessFromURLs(true);
settings.setAllowUniversalAccessFromURLs(true);
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Random r = new Random();
Random r = new Random(); // BAD: Random is not cryptographically secure

byte[] bytes = new byte[16];
r.nextBytes(bytes);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
SecureRandom r = new SecureRandom();
SecureRandom r = new SecureRandom(); // GOOD: SecureRandom is cryptographically secure

byte[] bytes = new byte[16];
r.nextBytes(bytes);
Expand Down
4 changes: 2 additions & 2 deletions java/ql/src/Security/CWE/CWE-367/TOCTOURace.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ public synchronized void act() {

public synchronized void bad(Resource r) {
if (r.isReady()) {
// r might no longer be ready, another thread might
// BAD: r might no longer be ready, another thread might
// have called setReady(false)
r.act();
}
}

public synchronized void good(Resource r) {
synchronized(r) {
synchronized(r) { // GOOD: r is locked
if (r.isReady()) {
r.act();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@

public MyObject deserialize(Socket sock) {
try(ObjectInputStream in = new ObjectInputStream(sock.getInputStream())) {
return (MyObject)in.readObject(); // unsafe
return (MyObject)in.readObject(); // BAD: in is from untrusted source
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
public MyObject deserialize(Socket sock) {
try(DataInputStream in = new DataInputStream(sock.getInputStream())) {
return new MyObject(in.readInt());
return new MyObject(in.readInt()); // GOOD: read only an int
}
}
1 change: 1 addition & 0 deletions java/ql/src/Security/CWE/CWE-522/LdapAuthUseLdap.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// BAD: LDAP authentication is used
String ldapUrl = "ldap://ad.your-server.com:389";
Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
Expand Down
1 change: 1 addition & 0 deletions java/ql/src/Security/CWE/CWE-522/LdapAuthUseLdaps.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// GOOD: LDAP connection using LDAPS
String ldapUrl = "ldaps://ad.your-server.com:636";
Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
Expand Down
1 change: 1 addition & 0 deletions java/ql/src/Security/CWE/CWE-522/LdapEnableSasl.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// GOOD: LDAP is used but SASL authentication is enabled
String ldapUrl = "ldap://ad.your-server.com:389";
Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
Expand Down
2 changes: 1 addition & 1 deletion java/ql/src/Security/CWE/CWE-611/XXEBad.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
public void parse(Socket sock) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
builder.parse(sock.getInputStream()); //unsafe
builder.parse(sock.getInputStream()); // BAD: DTD parsing is enabled
}
2 changes: 1 addition & 1 deletion java/ql/src/Security/CWE/CWE-611/XXEGood.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ public void disableDTDParse(Socket sock) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
DocumentBuilder builder = factory.newDocumentBuilder();
builder.parse(sock.getInputStream()); //safe
builder.parse(sock.getInputStream()); // GOOD: DTD parsing is disabled
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

public class HardcodedAWSCredentials {
public static void main(String[] args) {
//Hardcoded credentials for connecting to AWS services
// BAD: Hardcoded credentials for connecting to AWS services
//To fix the problem, use other approaches including AWS credentials file, environment variables, or instance/container credentials instead
AWSCredentials creds = new BasicAWSCredentials("ACCESS_KEY", "SECRET_KEY"); //sensitive call
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
private static final String p = "123456"; // hard-coded credential
private static final String p = "123456"; // BAD: hard-coded credential

public static void main(String[] args) throws SQLException {
String url = "jdbc:mysql://localhost/test";
String u = "admin"; // hard-coded credential
String u = "admin"; // BAD: hard-coded credential

getConn(url, u, p);
}
Expand Down
2 changes: 1 addition & 1 deletion java/ql/src/Security/CWE/CWE-835/InfiniteLoopBad.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
for (int i=0; i<10; i++) {
for (int j=0; i<10; j++) {
for (int j=0; i<10; j++) { // BAD: Potential infinite loop: i should be j
// do stuff
if (shouldBreak()) break;
}
Expand Down
2 changes: 1 addition & 1 deletion java/ql/src/Security/CWE/CWE-835/InfiniteLoopGood.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
for (int i=0; i<10; i++) {
for (int j=0; j<10; j++) {
for (int j=0; j<10; j++) { // GOOD: correct variable j
// do stuff
if (shouldBreak()) break;
}
Expand Down
1 change: 1 addition & 0 deletions java/ql/src/Security/CWE/CWE-925/Bad.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
public class ShutdownReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, final Intent intent) {
// BAD: The code does not check if the intent is an ACTION_SHUTDOWN intent
mainActivity.saveLocalData();
mainActivity.stopActivity();
}
Expand Down
1 change: 1 addition & 0 deletions java/ql/src/Security/CWE/CWE-925/Good.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
public class ShutdownReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, final Intent intent) {
// GOOD: The code checks if the intent is an ACTION_SHUTDOWN intent
if (!intent.getAction().equals(Intent.ACTION_SHUTDOWN)) {
return;
}
Expand Down