diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1313.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1313.html index a183443581..0ba24b69b4 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1313.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1313.html @@ -1,42 +1,23 @@ -

Hardcoding IP addresses is security-sensitive. It has led in the past to the following vulnerabilities:

+

IP addresses hardcoded in source code couple the application to a specific infrastructure configuration. Today’s services have an ever-changing +architecture due to their scaling and redundancy needs. When an IP address changes, every hardcoded occurrence must be found and updated, which has an +impact on development, delivery, and deployment:

-

Today’s services have an ever-changing architecture due to their scaling and redundancy needs. It is a mistake to think that a service will always -have the same IP address. When it does change, the hardcoded IP will have to be modified too. This will have an impact on the product development, -delivery, and deployment:

- -

Last but not least it has an effect on application security. Attackers might be able to decompile the code and thereby discover a potentially -sensitive address. They can perform a Denial of Service attack on the service, try to get access to the system, or try to spoof the IP address to -bypass security checks. Such attacks can always be possible, but in the case of a hardcoded IP address solving the issue will take more time, which -will increase an attack’s impact.

-

Ask Yourself Whether

-

The disclosed IP address is sensitive, e.g.:

- -

There is a risk if you answered yes to any of these questions.

-

Recommended Secure Coding Practices

-

Don’t hard-code the IP address in the source code, instead make it configurable with environment variables, configuration files, or a similar -approach. Alternatively, if confidentially is not required a domain name can be used since it allows to change the destination quickly without having -to rebuild the software.

-

Sensitive Code Example

-
-String ip = "192.168.12.42"; // Sensitive
-Socket socket = new Socket(ip, 6667);
-
-

Compliant Solution

-
-String ip = System.getenv("IP_ADDRESS"); // Compliant
-Socket socket = new Socket(ip, 6667);
-
-

Exceptions

-

No issue is reported for the following cases because they are not considered sensitive:

+

Why is this an issue?

+

Hardcoding an IP address embeds infrastructure configuration directly into the application. This means any change to the network environment—such +as moving a service to a different host or scaling horizontally—requires a code modification and a full redeployment. Unlike a domain name, a +hardcoded address also makes it harder to use different values across environments such as development, staging, and production.

+

What is the potential impact?

+

Environment coupling

+

A hardcoded IP address is the same in every environment the application runs in. This makes it difficult to point development, staging, and +production builds at different infrastructure without modifying the source code.

+

Increased deployment friction

+

Any change to the target host—such as migrating a service, scaling out, or rotating infrastructure—requires a code change and a full redeployment +cycle. This prevents operational teams from making infrastructure adjustments independently and slows down incident response.

+

Exceptions

+

No issue is reported for the following well-known, special-purpose addresses, as they do not represent configurable infrastructure endpoints:

-

See

+

How to fix it

+

Code examples

+

The following code contains a hardcoded IP address instead of reading it from configuration or environment variables.

+

Noncompliant code example

+
+String ip = "192.168.12.42"; // Noncompliant
+Socket socket = new Socket(ip, 6667);
+
+

Compliant solution

+
+String ip = System.getenv("IP_ADDRESS");
+Socket socket = new Socket(ip, 6667);
+
+

Resources

+

Standards

diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1313.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1313.json index c5985524ca..d2dc6f0718 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1313.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S1313.json @@ -1,6 +1,6 @@ { - "title": "Using hardcoded IP addresses is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "IP addresses should not be hardcoded", + "type": "CODE_SMELL", "code": { "impacts": { "SECURITY": "LOW" @@ -16,6 +16,7 @@ "cert" ], "defaultSeverity": "Minor", + "quickfix": "unknown", "ruleSpecification": "RSPEC-1313", "sqKey": "S1313", "scope": "Main", @@ -32,6 +33,5 @@ "CWE": [ 547 ] - }, - "quickfix": "unknown" + } } diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S2257.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S2257.html index ddf831cb97..c9e8bb7ae9 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S2257.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S2257.html @@ -1,27 +1,37 @@ -

The use of a non-standard algorithm is dangerous because a determined attacker may be able to break the algorithm and compromise whatever data has -been protected. Standard algorithms like SHA-256, SHA-384, SHA-512, …​ should be used instead.

-

This rule tracks creation of java.security.MessageDigest subclasses.

-

Recommended Secure Coding Practices

- -

Sensitive Code Example

-
+

Cryptographic operations should use proven, standard algorithms rather than custom implementations.

+

Why is this an issue?

+

Non-standard cryptographic algorithms are those that have not been publicly vetted by the security community or that implement cryptographic +primitives in a custom way. Creating a custom cryptographic algorithm by subclassing standard cryptographic base classes bypasses the rigorous testing +and peer review that established algorithms undergo. Custom implementations are likely to contain subtle flaws that could be exploited to break the +protection the algorithm is supposed to provide.

+

What is the potential impact?

+

Data compromise

+

When an attacker discovers a flaw in a custom cryptographic algorithm, they may be able to decrypt any data protected by it. Depending on the +application, this could expose passwords, personal data, financial records, or other sensitive information.

+

How to fix it

+

This rule detects custom implementations of java.security.MessageDigest.

+

Code examples

+

Noncompliant code example

+
 public class MyCryptographicAlgorithm extends MessageDigest {
   ...
 }
 
-

Compliant Solution

-
+

Compliant solution

+
 MessageDigest digest = MessageDigest.getInstance("SHA-256");
 
-

See

+

Resources

+

Documentation

+ +

Standards

diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S2257.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S2257.json index 15d1467fcc..fbff923741 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S2257.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S2257.json @@ -1,6 +1,6 @@ { - "title": "Using non-standard cryptographic algorithms is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "Custom cryptographic algorithms should not be used", + "type": "VULNERABILITY", "code": { "impacts": { "SECURITY": "HIGH" @@ -12,8 +12,10 @@ "func": "Constant\/Issue", "constantCost": "1d" }, + "quickfix": "unknown", "tags": [ - "cwe" + "cwe", + "former-hotspot" ], "defaultSeverity": "Critical", "ruleSpecification": "RSPEC-2257", @@ -34,6 +36,5 @@ "6.2.2", "8.3.7" ] - }, - "quickfix": "unknown" + } } diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4434.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4434.html index 9f42d3dec6..9679593420 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4434.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4434.html @@ -1,40 +1,47 @@

JNDI supports the deserialization of objects from LDAP directories, which can lead to remote code execution.

-

This rule raises an issue when an LDAP search query is executed with SearchControls configured to allow deserialization.

-

Ask Yourself Whether

- -

There is a risk if you answered yes to any of those questions.

-

Recommended Secure Coding Practices

-

It is recommended to disable deserialization of LDAP objects.

-

Sensitive Code Example

-
+

Why is this an issue?

+

JNDI can deserialize Java objects returned by an LDAP directory when SearchControls is configured with the +returningObjFlag parameter set to true. If the LDAP directory is untrusted or has been compromised, an attacker can inject a +malicious serialized object that executes arbitrary code on the server when deserialized.

+

What is the potential impact?

+

If successfully exploited, an attacker who can control the content of the LDAP directory can craft a malicious serialized object that, when +deserialized, executes arbitrary code on the server. This can lead to full system compromise, including data exfiltration, malware installation, or +lateral movement within the network.

+

How to fix it

+

Set the returningObjFlag parameter to false when constructing SearchControls to prevent JNDI from +deserializing objects returned by the LDAP directory.

+

Code examples

+

Noncompliant code example

+
 DirContext ctx = new InitialDirContext();
 // ...
 ctx.search(query, filter,
         new SearchControls(scope, countLimit, timeLimit, attributes,
-            true, // Noncompliant; allows deserialization
+            true, // Noncompliant: allows deserialization
             deref));
 
-

Compliant Solution

-
+

Compliant solution

+
 DirContext ctx = new InitialDirContext();
 // ...
 ctx.search(query, filter,
         new SearchControls(scope, countLimit, timeLimit, attributes,
-            false, // Compliant
+            false,
             deref));
 
-

See

+

Resources

+

Articles & blog posts

+ +

Standards

diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4434.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4434.json index f2070f4ee5..570ad4a1a3 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4434.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4434.json @@ -1,6 +1,6 @@ { - "title": "Allowing deserialization of LDAP objects is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "Deserialization of Java objects from LDAP should be disabled", + "type": "VULNERABILITY", "code": { "impacts": { "SECURITY": "MEDIUM" @@ -13,7 +13,8 @@ "constantCost": "2min" }, "tags": [ - "cwe" + "cwe", + "former-hotspot" ], "defaultSeverity": "Major", "ruleSpecification": "RSPEC-4434", diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4512.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4512.html index 42ebd686f7..6138c4c471 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4512.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4512.html @@ -1,31 +1,18 @@ -

Setting JavaBean properties is security sensitive. Doing it with untrusted values has led in the past to the following vulnerability:

- -

JavaBeans can have their properties or nested properties set by population functions. An attacker can leverage this feature to push into the -JavaBean malicious data that can compromise the software integrity. A typical attack will try to manipulate the ClassLoader and finally execute -malicious code.

-

This rule raises an issue when:

-
    -
  • BeanUtils.populate(…​) or BeanUtilsBean.populate(…​) from Apache Commons - BeanUtils are called
  • -
  • BeanUtils.setProperty(…​) or BeanUtilsBean.setProperty(…​) from Apache Commons - BeanUtils are called
  • -
  • org.springframework.beans.BeanWrapper.setPropertyValue(…​) or org.springframework.beans.BeanWrapper.setPropertyValues(…​) from Spring is - called
  • -
-

Ask Yourself Whether

-
    -
  • the new property values might have been tampered with or provided by an untrusted source.
  • -
  • sensitive properties can be modified, for example: class.classLoader
  • -
-

There is a risk if you answered yes to any of those questions.

-

Recommended Secure Coding Practices

-

Sanitize all values used as JavaBean properties.

-

Don’t set any sensitive properties. Keep full control over which properties are set. If the property names are provided by an unstrusted source, -filter them with a whitelist.

-

Sensitive Code Example

-
+

Setting JavaBean properties from untrusted user input can allow an attacker to manipulate arbitrary object properties, including sensitive +internals such as class.classLoader.

+

Why is this an issue?

+

JavaBean property population functions such as BeanUtils.populate(), BeanUtils.setProperty(), +BeanUtilsBean.populate(), and BeanUtilsBean.setProperty() from Apache Commons BeanUtils, and +BeanWrapper.setPropertyValue() and BeanWrapper.setPropertyValues() from Spring, allow setting arbitrary bean properties by +name. When the property names or values are derived from untrusted input without validation, an attacker can set sensitive properties — for example, +class.classLoader — and use them to load and execute malicious code.

+

What is the potential impact?

+

If successfully exploited, this vulnerability can lead to remote code execution, full application compromise, data exfiltration, or lateral +movement within the network.

+

How to fix it

+

Code examples

+

Noncompliant code example

+
 Company bean = new Company();
 HashMap map = new HashMap();
 Enumeration names = request.getParameterNames();
@@ -33,17 +20,35 @@ 

Sensitive Code Example

String name = (String) names.nextElement(); map.put(name, request.getParameterValues(name)); } -BeanUtils.populate(bean, map); // Sensitive: "map" is populated with data coming from user input, here "request.getParameterNames()" +BeanUtils.populate(bean, map); // Noncompliant: "map" is populated with data coming from user input, here "request.getParameterNames()"
-

See

+

Compliant solution

+
+Company bean = new Company();
+HashMap map = new HashMap();
+Set<String> allowedProperties = Set.of("name", "address"); // define allowed properties
+Enumeration names = request.getParameterNames();
+while (names.hasMoreElements()) {
+    String name = (String) names.nextElement();
+    if (allowedProperties.contains(name)) {
+        map.put(name, request.getParameterValues(name));
+    }
+}
+BeanUtils.populate(bean, map);
+
+

Resources

+

Articles & blog posts

+ +

Standards

diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4512.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4512.json index 475d991a75..311e6924b8 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4512.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4512.json @@ -1,6 +1,6 @@ { - "title": "Setting JavaBean properties is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "JavaBean properties should not be populated from untrusted input", + "type": "VULNERABILITY", "code": { "impacts": { "SECURITY": "HIGH" @@ -14,7 +14,8 @@ }, "tags": [ "cwe", - "cert" + "cert", + "former-hotspot" ], "defaultSeverity": "Critical", "ruleSpecification": "RSPEC-4512", diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4544.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4544.html index 4e269ebf53..a07e7557db 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4544.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4544.html @@ -1,53 +1,53 @@ -

Using unsafe Jackson deserialization configuration is security-sensitive. It has led in the past to the following vulnerabilities:

- +

Jackson can be configured to allow Polymorphic Type Handling, which may expose the application to deserialization attacks.

+

Why is this an issue?

When Jackson is configured to allow Polymorphic Type Handling (aka PTH), formerly known as Polymorphic Deserialization, "deserialization gadgets" may allow an attacker to perform remote code execution.

This rule raises an issue when:

  • enableDefaultTyping() is called on an instance of com.fasterxml.jackson.databind.ObjectMapper or org.codehaus.jackson.map.ObjectMapper.
  • -
  • or when the annotation @JsonTypeInfo is set at class, interface or field levels and configured with use = +
  • The annotation @JsonTypeInfo is set at class, interface or field levels and configured with use = JsonTypeInfo.Id.CLASS or use = Id.MINIMAL_CLASS.
-

Ask Yourself Whether

-
    -
  • You configured the Jackson deserializer as mentioned above.
  • -
  • The serialized data might come from an untrusted source.
  • -
-

There is a risk if you answered yes to any of those questions.

-

Recommended Secure Coding Practices

-
    -
  • Use the latest patch versions of jackson-databind blocking the already discovered "deserialization gadgets".
  • -
  • Avoid using the default typing configuration: ObjectMapper.enableDefaultTyping().
  • -
  • If possible, use @JsonTypeInfo(use = Id.NAME) instead of @JsonTypeInfo(use = Id.CLASS) or @JsonTypeInfo(use = - Id. MINIMAL_CLASS) and so rely on @JsonTypeName and @JsonSubTypes.
  • -
-

Sensitive Code Example

-
+

What is the potential impact?

+

If an attacker can control the serialized data, they can craft malicious payloads that exploit deserialization gadgets present on the classpath. +This can lead to remote code execution, allowing the attacker to run arbitrary commands on the server.

+

How to fix it

+

Code examples

+

Noncompliant code example

+
 ObjectMapper mapper = new ObjectMapper();
-mapper.enableDefaultTyping(); // Sensitive
+mapper.enableDefaultTyping(); // Noncompliant
+
+@JsonTypeInfo(use = Id.CLASS) // Noncompliant
+abstract class PhoneNumber {
+}
 
-
-@JsonTypeInfo(use = Id.CLASS) // Sensitive
+

Compliant solution

+
+ObjectMapper mapper = new ObjectMapper();
+
+@JsonTypeInfo(use = Id.NAME)
 abstract class PhoneNumber {
 }
 
-

See

+

Resources

+

Documentation

+ +

Articles & blog posts

+ +

Standards

diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4544.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4544.json index 1efcbc2143..c1bee764a4 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4544.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S4544.json @@ -1,6 +1,11 @@ { - "title": "Using unsafe Jackson deserialization configuration is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "Jackson deserialization should not use unsafe configuration", + "type": "VULNERABILITY", + "quickfix": "unknown", + "tags": [ + "cwe", + "former-hotspot" + ], "code": { "impacts": { "SECURITY": "HIGH" @@ -12,9 +17,6 @@ "func": "Constant\/Issue", "constantCost": "15min" }, - "tags": [ - "cwe" - ], "defaultSeverity": "Critical", "ruleSpecification": "RSPEC-4544", "sqKey": "S4544", @@ -40,6 +42,5 @@ "5.5.1", "5.5.3" ] - }, - "quickfix": "unknown" + } } diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5042.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5042.html index bdefae31c1..a599878dbe 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5042.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5042.html @@ -1,28 +1,26 @@ +

This rule is deprecated, and will eventually be removed.

Successful Zip Bomb attacks occur when an application expands untrusted archive files without controlling the size of the expanded data, which can lead to denial of service. A Zip bomb is usually a malicious archive file of a few kilobytes of compressed data but turned into gigabytes of uncompressed data. To achieve this extreme compression ratio, attackers will compress irrelevant data (eg: a long string of repeated bytes).

-

Ask Yourself Whether

-

Archives to expand are untrusted and:

-
    -
  • There is no validation of the number of entries in the archive.
  • -
  • There is no validation of the total size of the uncompressed data.
  • -
  • There is no validation of the ratio between the compressed and uncompressed archive entry.
  • -
-

There is a risk if you answered yes to any of those questions.

-

Recommended Secure Coding Practices

-
    -
  • Define and control the ratio between compressed and uncompressed data, in general the data compression ratio for most of the legit archives is 1 - to 3.
  • -
  • Define and control the threshold for maximum total size of the uncompressed data.
  • -
  • Count the number of file entries extracted from the archive and abort the extraction if their number is greater than a predefined threshold, in - particular it’s not recommended to recursively expand archives (an entry of an archive could be also an archive).
  • -
-

Sensitive Code Example

-
+

Why is this an issue?

+

Expanding archive files without controlling the size of the extracted data can lead to denial of service. A Zip bomb is a malicious archive of a +few kilobytes of compressed data that expands into gigabytes of uncompressed data by compressing highly repetitive content. Applications that fail to +validate the number of entries, total uncompressed size, or compression ratio of an archive are vulnerable to this attack.

+

What is the potential impact?

+

Denial of service

+

An attacker who can supply a malicious archive can exhaust the server’s disk space, memory, or CPU by triggering unbounded decompression. This can +make the application completely unavailable to legitimate users and may require manual intervention to recover the affected system.

+

How to fix it in Java SE

+

Validate the number of entries, total uncompressed size, and compression ratio when extracting archive files. Do not rely on getSize to retrieve the uncompressed size, as this value +comes from archive headers that can be forged; calculate the actual size while reading.

+

Code examples

+

Noncompliant code example

+
 File f = new File("ZipBomb.zip");
 ZipFile zipFile = new ZipFile(f);
-Enumeration<? extends ZipEntry> entries = zipFile.entries(); // Sensitive
+Enumeration<? extends ZipEntry> entries = zipFile.entries(); // Noncompliant
 
 while(entries.hasMoreElements()) {
   ZipEntry ze = entries.nextElement();
@@ -30,19 +28,16 @@ 

Sensitive Code Example

Files.copy(zipFile.getInputStream(ze), out.toPath(), StandardCopyOption.REPLACE_EXISTING); }
-

Compliant Solution

-

Do not rely on getsize to retrieve the size of an -uncompressed entry because this method returns what is defined in the archive headers which can be forged by attackers, instead calculate the actual -entry size when unzipping it:

-
+

Compliant solution

+
 File f = new File("ZipBomb.zip");
 ZipFile zipFile = new ZipFile(f);
 Enumeration<? extends ZipEntry> entries = zipFile.entries();
 
 int THRESHOLD_ENTRIES = 10000;
-int THRESHOLD_SIZE = 1000000000; // 1 GB
+long THRESHOLD_SIZE = 1000000000L; // 1 GB
 double THRESHOLD_RATIO = 10;
-int totalSizeArchive = 0;
+long totalSizeArchive = 0;
 int totalEntryArchive = 0;
 
 while(entries.hasMoreElements()) {
@@ -56,7 +51,7 @@ 

Compliant Solution

byte[] buffer = new byte[2048]; int totalSizeEntry = 0; - while((nBytes = in.read(buffer)) > 0) { // Compliant + while((nBytes = in.read(buffer)) > 0) { out.write(buffer, 0, nBytes); totalSizeEntry += nBytes; totalSizeArchive += nBytes; @@ -79,7 +74,12 @@

Compliant Solution

} }
-

See

+

Resources

+

Articles & blog posts

+ +

Standards

diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5042.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5042.json index 971b1ad13f..3aaf2a2bd3 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5042.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5042.json @@ -1,22 +1,24 @@ { - "title": "Expanding archive files without controlling resource consumption is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "Expanding archive files should not be done without controlling resource consumption", + "type": "CODE_SMELL", + "quickfix": "unknown", "code": { "impacts": { - "SECURITY": "HIGH" + "RELIABILITY": "MEDIUM" }, "attribute": "COMPLETE" }, - "status": "ready", + "status": "deprecated", "remediation": { "func": "Constant\/Issue", "constantCost": "10min" }, "tags": [ "cwe", - "cert" + "cert", + "former-hotspot" ], - "defaultSeverity": "Critical", + "defaultSeverity": "Minor", "ruleSpecification": "RSPEC-5042", "sqKey": "S5042", "scope": "Main", @@ -38,6 +40,5 @@ "ASVS 4.0": [ "12.1.2" ] - }, - "quickfix": "unknown" + } } diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5122.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5122.html index 5893c2ead0..8c9f1a3227 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5122.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5122.html @@ -1,46 +1,55 @@ -

Having a permissive Cross-Origin Resource Sharing policy is security-sensitive. It has led in the past to the following vulnerabilities:

- -

Same origin policy in browsers prevents, by default and for -security-reasons, a javascript frontend to perform a cross-origin HTTP request to a resource that has a different origin (domain, protocol, or port) -from its own. The requested target can append additional HTTP headers in response, called CORS, that act like directives for the browser and change the access control policy -/ relax the same origin policy.

-

Ask Yourself Whether

-
    -
  • You don’t trust the origin specified, example: Access-Control-Allow-Origin: untrustedwebsite.com.
  • -
  • Access control policy is entirely disabled: Access-Control-Allow-Origin: *
  • -
  • Your access control policy is dynamically defined by a user-controlled input like origin header.
  • -
-

There is a risk if you answered yes to any of those questions.

-

Recommended Secure Coding Practices

-
    -
  • The Access-Control-Allow-Origin header should be set only for a trusted origin and for specific resources.
  • -
  • Allow only selected, trusted domains in the Access-Control-Allow-Origin header. Prefer whitelisting domains over blacklisting or - allowing any domain (do not use * wildcard nor blindly return the Origin header content without any checks).
  • -
-

Sensitive Code Example

-

Java servlet framework:

-
+

Setting an overly permissive Cross-Origin Resource Sharing (CORS) policy allows malicious websites to read responses from your application on +behalf of authenticated users.

+

Why is this an issue?

+

Same-origin policy in browsers prevents JavaScript from +making cross-origin HTTP requests to resources with a different origin (domain, protocol, or port). The Cross-Origin Resource Sharing (CORS) mechanism allows servers to relax this +restriction by including Access-Control-Allow-Origin response headers that tell browsers which origins are permitted.

+

Setting the Access-Control-Allow-Origin header to a wildcard (*) or dynamically reflecting a user-supplied +Origin header without validation completely disables same-origin protection for the affected resource.

+

What is the potential impact?

+

Sensitive data exposure

+

When CORS restrictions are disabled, a malicious website visited by an authenticated user can issue cross-origin requests to the vulnerable +application and read the responses. This allows attackers to steal sensitive data accessible to the victim, such as account details, API keys, or +private application data.

+

Account takeover

+

If the application is also configured with Access-Control-Allow-Credentials: true, the browser will include cookies and HTTP +authentication headers in cross-origin requests. Attackers can then perform authenticated operations on behalf of the victim, potentially leading to +full account takeover or unauthorized data modification.

+

How to fix it in Servlet

+

Set the Access-Control-Allow-Origin header to a specific trusted origin.

+

Code examples

+

Noncompliant code example

+
 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
     resp.setHeader("Content-Type", "text/plain; charset=utf-8");
-    resp.setHeader("Access-Control-Allow-Origin", "*"); // Sensitive
+    resp.setHeader("Access-Control-Allow-Origin", "*"); // Noncompliant
     resp.setHeader("Access-Control-Allow-Credentials", "true");
     resp.setHeader("Access-Control-Allow-Methods", "GET");
     resp.getWriter().write("response");
 }
 
-

Spring MVC framework:

- -
-@CrossOrigin // Sensitive
+

Compliant solution

+
+@Override
+protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+    resp.setHeader("Content-Type", "text/plain; charset=utf-8");
+    resp.setHeader("Access-Control-Allow-Origin", "https://trustedwebsite.com");
+    resp.setHeader("Access-Control-Allow-Credentials", "true");
+    resp.setHeader("Access-Control-Allow-Methods", "GET");
+    resp.getWriter().write("response");
+}
+
+

How to fix it in Spring

+

Use Spring’s CORS configuration to restrict allowed origins to specific trusted domains, and validate user-supplied origins against an +allow-list.

+

Code examples

+

Noncompliant code example

+

CrossOrigin +annotation:

+
+@CrossOrigin // Noncompliant
 @RequestMapping("")
 public class TestController {
     public String home(ModelMap model) {
@@ -49,56 +58,39 @@ 

Sensitive Code Example

} }
- -
+

cors.CorsConfiguration +class:

+
 CorsConfiguration config = new CorsConfiguration();
-config.addAllowedOrigin("*"); // Sensitive
-config.applyPermitDefaultValues(); // Sensitive
+config.addAllowedOrigin("*"); // Noncompliant
+config.applyPermitDefaultValues(); // Noncompliant
 
- -
+

servlet.config.annotation.CorsRegistration:

+
 class Insecure implements WebMvcConfigurer {
   @Override
   public void addCorsMappings(CorsRegistry registry) {
     registry.addMapping("/**")
-      .allowedOrigins("*"); // Sensitive
+      .allowedOrigins("*"); // Noncompliant
   }
 }
 

User-controlled origin:

-
+
 public ResponseEntity<String> userControlledOrigin(@RequestHeader("Origin") String origin) {
   HttpHeaders responseHeaders = new HttpHeaders();
-  responseHeaders.add("Access-Control-Allow-Origin", origin); // Sensitive
+  responseHeaders.add("Access-Control-Allow-Origin", origin); // Noncompliant
 
   return new ResponseEntity<>("content", responseHeaders, HttpStatus.CREATED);
 }
 
-

Compliant Solution

-

Java Servlet framework:

-
-@Override
-protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-    resp.setHeader("Content-Type", "text/plain; charset=utf-8");
-    resp.setHeader("Access-Control-Allow-Origin", "trustedwebsite.com"); // Compliant
-    resp.setHeader("Access-Control-Allow-Credentials", "true");
-    resp.setHeader("Access-Control-Allow-Methods", "GET");
-    resp.getWriter().write("response");
-}
-
-

Spring MVC framework:

- -
-@CrossOrigin("trustedwebsite.com") // Compliant
+

Compliant solution

+

CrossOrigin +annotation:

+
+@CrossOrigin("https://trustedwebsite.com")
 @RequestMapping("")
 public class TestController {
     public String home(ModelMap model) {
@@ -107,29 +99,26 @@ 

Compliant Solution

} }
- -
+

cors.CorsConfiguration +class:

+
 CorsConfiguration config = new CorsConfiguration();
-config.addAllowedOrigin("http://domain2.com"); // Compliant
+config.addAllowedOrigin("http://domain2.com");
 
- -
+

servlet.config.annotation.CorsConfiguration:

+
 class Safe implements WebMvcConfigurer {
   @Override
   public void addCorsMappings(CorsRegistry registry) {
     registry.addMapping("/**")
-      .allowedOrigins("safe.com"); // Compliant
+      .allowedOrigins("https://safe.com");
   }
 }
 

User-controlled origin validated with an allow-list:

-
+
 public ResponseEntity<String> userControlledOrigin(@RequestHeader("Origin") String origin) {
   HttpHeaders responseHeaders = new HttpHeaders();
   if (trustedOrigins.contains(origin)) {
@@ -139,17 +128,21 @@ 

Compliant Solution

return new ResponseEntity<>("content", responseHeaders, HttpStatus.CREATED); }
-

See

+

Resources

+

Documentation

+ +

Standards

diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5122.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5122.json index a37580e7ac..57fe93f99a 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5122.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5122.json @@ -1,18 +1,24 @@ { - "title": "Having a permissive Cross-Origin Resource Sharing policy is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "Cross-Origin Resource Sharing (CORS) policy should be restricted to trusted origins", + "type": "VULNERABILITY", "code": { "impacts": { - "SECURITY": "LOW" + "SECURITY": "MEDIUM" }, "attribute": "COMPLETE" }, "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "4h" + }, + "quickfix": "unknown", "tags": [ "cwe", - "spring" + "spring", + "former-hotspot" ], - "defaultSeverity": "Minor", + "defaultSeverity": "Major", "ruleSpecification": "RSPEC-5122", "sqKey": "S5122", "scope": "Main", @@ -38,6 +44,5 @@ "14.5.2", "14.5.3" ] - }, - "quickfix": "unknown" + } } diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5320.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5320.html index fb2f460341..395fce4abb 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5320.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5320.html @@ -1,21 +1,22 @@ -

In Android applications, broadcasting intents is security-sensitive. For example, it has led in the past to the following vulnerability:

- -

By default, broadcasted intents are visible to every application, exposing all sensitive information they contain.

-

This rule raises an issue when an intent is broadcasted without specifying any "receiver permission".

-

Ask Yourself Whether

-
    -
  • The intent contains sensitive information.
  • -
  • Intent reception is not restricted.
  • -
-

There is a risk if you answered yes to any of those questions.

-

Recommended Secure Coding Practices

-

Restrict the access to broadcasted intents. See Android documentation for more -information.

-

Sensitive Code Example

-
+

Broadcasted intents in Android are visible to every application by default, which can expose sensitive information.

+

Why is this an issue?

+

By default, broadcasted intents are visible to every application on the device, exposing all sensitive information that intents contain. This rule +raises an issue when an intent is broadcasted without specifying a receiver permission.

+

Methods like sendBroadcast, sendBroadcastAsUser, sendOrderedBroadcast, and +sendOrderedBroadcastAsUser that are called without a receiver permission parameter or with null for the permission allow any +application to receive the broadcast.

+

What is the potential impact?

+

Information disclosure

+

If an intent contains sensitive data such as user credentials, personal information, or internal application state, any malicious application +installed on the same device can intercept and read this data.

+

Privilege escalation

+

A malicious application could listen for broadcasted intents to trigger unauthorized actions or manipulate application behavior, potentially +gaining access to functionality that should be restricted.

+

How to fix it

+

Code examples

+

The following code broadcasts an intent without specifying a receiver permission, making it accessible to all applications on the device.

+

Noncompliant code example

+
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -31,20 +32,20 @@ 

Sensitive Code Example

BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras, String broadcastPermission) { - context.sendBroadcast(intent); // Sensitive - context.sendBroadcastAsUser(intent, user); // Sensitive + context.sendBroadcast(intent); // Noncompliant + context.sendBroadcastAsUser(intent, user); // Noncompliant // Broadcasting intent with "null" for receiverPermission - context.sendBroadcast(intent, null); // Sensitive - context.sendBroadcastAsUser(intent, user, null); // Sensitive - context.sendOrderedBroadcast(intent, null); // Sensitive + context.sendBroadcast(intent, null); // Noncompliant + context.sendBroadcastAsUser(intent, user, null); // Noncompliant + context.sendOrderedBroadcast(intent, null); // Noncompliant context.sendOrderedBroadcastAsUser(intent, user, null, resultReceiver, - scheduler, initialCode, initialData, initialExtras); // Sensitive + scheduler, initialCode, initialData, initialExtras); // Noncompliant } }
-

Compliant Solution

-
+

Compliant solution

+
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -64,12 +65,18 @@ 

Compliant Solution

context.sendBroadcast(intent, broadcastPermission); context.sendBroadcastAsUser(intent, user, broadcastPermission); context.sendOrderedBroadcast(intent, broadcastPermission); - context.sendOrderedBroadcastAsUser(intent, user,broadcastPermission, resultReceiver, + context.sendOrderedBroadcastAsUser(intent, user, broadcastPermission, resultReceiver, scheduler, initialCode, initialData, initialExtras); } }
-

See

+

Resources

+

Documentation

+ +

Standards

diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5320.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5320.json index 1e8c5fa217..f797943a9e 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5320.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5320.json @@ -1,18 +1,23 @@ { - "title": "Broadcasting intents is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "Intents should not be broadcast without receiver permissions", + "type": "VULNERABILITY", "code": { "impacts": { - "SECURITY": "HIGH" + "SECURITY": "MEDIUM" }, "attribute": "COMPLETE" }, "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "10min" + }, "tags": [ "cwe", - "android" + "android", + "former-hotspot" ], - "defaultSeverity": "Critical", + "defaultSeverity": "Major", "ruleSpecification": "RSPEC-5320", "sqKey": "S5320", "scope": "Main", diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5322.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5322.html index 3501d3dc3e..5434867b02 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5322.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5322.html @@ -1,29 +1,22 @@ -

Android applications can receive broadcasts from the system or other applications. Receiving intents is security-sensitive. For example, it has led -in the past to the following vulnerabilities:

- -

Receivers can be declared in the manifest or in the code to make them context-specific. If the receiver is declared in the manifest Android will -start the application if it is not already running once a matching broadcast is received. The receiver is an entry point into the application.

-

Other applications can send potentially malicious broadcasts, so it is important to consider broadcasts as untrusted and to limit the applications -that can send broadcasts to the receiver.

-

Permissions can be specified to restrict broadcasts to authorized applications. Restrictions can be enforced by both the sender and receiver of a -broadcast. If permissions are specified when registering a broadcast receiver, then only broadcasters who were granted this permission can send a -message to the receiver.

-

This rule raises an issue when a receiver is registered without specifying any broadcast permission.

-

Ask Yourself Whether

-
    -
  • The data extracted from intents is not sanitized.
  • -
  • Intents broadcast is not restricted.
  • -
-

There is a risk if you answered yes to any of those questions.

-

Recommended Secure Coding Practices

-

Restrict the access to broadcasted intents. See the Android documentation for more -information.

-

Sensitive Code Example

-
+

Android applications can receive broadcasts from the system or other applications through registered broadcast receivers.

+

Why is this an issue?

+

A broadcast receiver registered or declared without a broadcast permission can receive intents from any application on the device, making it an +unrestricted entry point into the application. Malicious or compromised applications can send crafted broadcasts that trigger unintended behavior, +bypass access controls, or feed untrusted data into the application’s processing logic. This rule raises an issue when a receiver is registered in +code without a broadcastPermission argument, or when a receiver is declared in the manifest as exported without an +android:permission attribute.

+

What is the potential impact?

+

Unauthorized access

+

An attacker controlling a malicious application can send arbitrary broadcasts to the unprotected receiver, potentially triggering sensitive +operations such as changing application state or invoking privileged functionality without the user’s knowledge.

+

Data injection

+

Without restriction, any application can supply arbitrary intent data to the receiver. If that data is processed without validation, it can lead to +logic errors or further exploitation within the application.

+

How to fix it

+

Code examples

+

The following code registers a broadcast receiver without specifying a broadcast permission, allowing any application to send intents to it.

+

Noncompliant code example

+
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.IntentFilter;
@@ -39,17 +32,17 @@ 

Sensitive Code Example

String broadcastPermission, Handler scheduler, int flags) { - context.registerReceiver(receiver, filter); // Sensitive - context.registerReceiver(receiver, filter, flags); // Sensitive + context.registerReceiver(receiver, filter); // Noncompliant + context.registerReceiver(receiver, filter, flags); // Noncompliant // Broadcasting intent with "null" for broadcastPermission - context.registerReceiver(receiver, filter, null, scheduler); // Sensitive - context.registerReceiver(receiver, filter, null, scheduler, flags); // Sensitive + context.registerReceiver(receiver, filter, null, scheduler); // Noncompliant + context.registerReceiver(receiver, filter, null, scheduler, flags); // Noncompliant } }
-

Compliant Solution

-
+

Compliant solution

+
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.IntentFilter;
@@ -71,8 +64,16 @@ 

Compliant Solution

} }
-

See

+

Resources

+

Documentation

+ +

Standards

diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5322.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5322.json index 90110e40ae..87228f53c2 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5322.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5322.json @@ -1,6 +1,11 @@ { - "title": "Receiving intents is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "Android broadcast receivers should not be registered without a permission", + "type": "VULNERABILITY", + "quickfix": "unknown", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "15min" + }, "code": { "impacts": { "SECURITY": "HIGH" @@ -10,7 +15,8 @@ "status": "ready", "tags": [ "cwe", - "android" + "android", + "former-hotspot" ], "defaultSeverity": "Critical", "ruleSpecification": "RSPEC-5322", @@ -31,6 +37,5 @@ "MASVS": [ "MSTG-PLATFORM-2" ] - }, - "quickfix": "unknown" + } } diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5324.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5324.html index 4168b40f2f..fe780b822e 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5324.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5324.html @@ -1,38 +1,34 @@ -

Storing data locally is a common task for mobile applications. Such data includes files among other things. One convenient way to store files is to -use the external file storage which usually offers a larger amount of disc space compared to internal storage.

-

Files created on the external storage are globally readable and writable. Therefore, a malicious application having the permissions -WRITE_EXTERNAL_STORAGE or READ_EXTERNAL_STORAGE could try to read sensitive information from the files that other -applications have stored on the external storage.

-

External storage can also be removed by the user (e.g. when based on SD card) making the files unavailable to the application.

-

Ask Yourself Whether

-

Your application uses external storage to:

-
    -
  • store files that contain sensitive data.
  • -
  • store files that are not meant to be shared with other application.
  • -
  • store files that are critical for the application to work.
  • -
-

There is a risk if you answered yes to any of those questions.

-

Recommended Secure Coding Practices

-
    -
  • Use internal storage whenever possible as the system prevents other apps from accessing this location.
  • -
  • Only use external storage if you need to share non-sensitive files with other applications.
  • -
  • If your application has to use the external storage to store sensitive data, make sure it encrypts the files using EncryptedFile.
  • -
  • Data coming from external storage should always be considered untrusted and should be validated.
  • -
  • As some external storage can be removed, make sure to never store files on it that are critical for the usability of your application.
  • -
-

Sensitive Code Example

+

Android applications can store files on external storage (such as an SD card or shared storage), which is globally readable and writable by other +applications.

+

Why is this an issue?

+

External storage in Android is globally readable and writable by any application that holds the READ_EXTERNAL_STORAGE or +WRITE_EXTERNAL_STORAGE permissions. Files stored there can be read, modified, or deleted by other applications, making external storage +unsuitable for sensitive data. External storage can also be physically removed by the user, causing files to become unavailable at any time. This rule +raises an issue when an application accesses external storage directories via APIs such as getExternalFilesDir, +getExternalStorageDirectory, or equivalent.

+

What is the potential impact?

+

Data exposure

+

A malicious application with storage permissions can read sensitive files stored in external storage, leading to exposure of user credentials, +personal data, or application secrets.

+

Data integrity

+

An attacker can modify or delete files in external storage, corrupting application data or injecting malicious content that the application will +later process.

+

How to fix it

+

Code examples

+

The following code accesses external storage, which is globally readable and writable by other applications and therefore should not be used to +store sensitive data.

+

Noncompliant code example

 import android.content.Context;
 
 public class AccessExternalFiles {
 
     public void accessFiles(Context context) {
-        context.getExternalFilesDir(null); // Sensitive
+        context.getExternalFilesDir(null); // Noncompliant
     }
 }
 
-

Compliant Solution

+

Compliant solution

 import android.content.Context;
 
@@ -43,11 +39,15 @@ 

Compliant Solution

} }
-

See

+

Resources

+

Documentation

+

Standards

+
    +
  • OWASP - Top 10 2021 Category A4 - Insecure Design
  • OWASP - Mobile AppSec Verification Standard - Data Storage and Privacy Requirements
  • OWASP - Mobile Top 10 2016 Category M2 - Insecure Data diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5324.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5324.json index b3346163fd..ab22f97e5b 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5324.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5324.json @@ -1,6 +1,6 @@ { - "title": "Accessing Android external storage is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "Sensitive data should not be stored in Android external storage", + "type": "VULNERABILITY", "code": { "impacts": { "SECURITY": "HIGH" @@ -8,9 +8,14 @@ "attribute": "COMPLETE" }, "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "1h" + }, "tags": [ "cwe", - "android" + "android", + "former-hotspot" ], "defaultSeverity": "Critical", "ruleSpecification": "RSPEC-5324", diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5443.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5443.html index 612b4d9a7a..3abb4405e9 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5443.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5443.html @@ -1,14 +1,11 @@ -

    Operating systems have global directories where any user has write access. Those folders are mostly used as temporary storage areas like -/tmp in Linux based systems. An application manipulating files from these folders is exposed to race conditions on filenames: a malicious -user can try to create a file with a predictable name before the application does. A successful attack can result in other files being accessed, -modified, corrupted or deleted. This risk is even higher if the application runs with elevated permissions.

    -

    In the past, it has led to the following vulnerabilities:

    -
    -

    This rule raises an issue whenever it detects a hard-coded path to a publicly writable directory like /tmp (see examples below). It -also detects access to environment variables that point to publicly writable directories, e.g., TMP and TMPDIR.

    +

    Using publicly writable directories such as /tmp to store temporary files exposes an application to race condition +vulnerabilities.

    +

    Why is this an issue?

    +

    Operating systems provide globally writable directories—such as /tmp on Linux or \Windows\Temp on Windows—where any user +can create, read, and modify files. When an application creates files in these directories with predictable names, it becomes vulnerable to race +conditions: an attacker can create a file with the same name before the application does, potentially causing the application to read or write +attacker-controlled content.

    +

    This rule raises an issue when it detects hard-coded paths to publicly writable directories, such as:

    • /tmp
    • /var/tmp
    • @@ -24,38 +21,36 @@
    • \Windows\Temp
    • \Temp
    • \TMP
    • +
    • %USERPROFILE%\AppData\Local\Temp
    -

    Ask Yourself Whether

    -
      -
    • Files are read from or written into a publicly writable folder
    • -
    • The application creates files with predictable names into a publicly writable folder
    • -
    -

    There is a risk if you answered yes to any of those questions.

    -

    Recommended Secure Coding Practices

    -
      -
    • Use a dedicated sub-folder with tightly controlled permissions
    • -
    • Use secure-by-design APIs to create temporary files. Such API will make sure: -
        -
      • The generated filename is unpredictable
      • -
      • The file is readable and writable only by the creating user ID
      • -
      • The file descriptor is not inherited by child processes
      • -
      • The file will be destroyed as soon as it is closed
      • -
    • -
    -

    Sensitive Code Example

    -
    -new File("/tmp/myfile.txt"); // Sensitive
    -Paths.get("/tmp/myfile.txt"); // Sensitive
    +

    It also raises an issue when it detects reads of environment variables that point to publicly writable directories: TMP, +TMPDIR, and TEMP.

    +

    What is the potential impact?

    +

    Information disclosure

    +

    By winning the race condition, an attacker can access files written by the application to a publicly writable directory. If those files contain +sensitive data—credentials, session tokens, or personal information—the attacker can read them before the application removes them.

    +

    Data tampering

    +

    An attacker can replace or modify a file before the application reads it, causing the application to process attacker-controlled content. This can +result in data corruption, unexpected behavior, or indirect code execution. The risk is significantly higher when the application runs with elevated +privileges.

    +

    How to fix it in Java SE

    +

    Use the secure-by-design APIs from java.io and java.nio that create temporary files with unpredictable names and +appropriate permissions.

    +

    Code examples

    +

    Noncompliant code example

    +
    +new File("/tmp/myfile.txt"); // Noncompliant
    +Paths.get("/tmp/myfile.txt"); // Noncompliant
     
    -java.io.File.createTempFile("prefix", "suffix"); // Sensitive, will be in the default temporary-file directory.
    -java.nio.file.Files.createTempDirectory("prefix"); // Sensitive, will be in the default temporary-file directory.
    +java.io.File.createTempFile("prefix", "suffix"); // Noncompliant: will be in the default temporary-file directory.
    +java.nio.file.Files.createTempDirectory("prefix"); // Noncompliant: will be in the default temporary-file directory.
     
    -
    +
     Map<String, String> env = System.getenv();
    -env.get("TMP"); // Sensitive
    +env.get("TMP"); // Noncompliant
     
    -

    Compliant Solution

    -
    +

    Compliant solution

    +
     new File("/myDirectory/myfile.txt");  // Compliant
     
     File.createTempFile("prefix", "suffix", new File("/mySecureDirectory"));  // Compliant
    @@ -71,7 +66,15 @@ 

    Compliant Solution

    f.setExecutable(true, true); }
    -

    See

    +
    +File.createTempFile("prefix", "suffix", new File("/mySecureDirectory"));  // Compliant
    +
    +

    Resources

    +

    Articles & blog posts

    + +

    Standards

    diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5443.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5443.json index 8836c7bdc7..9c72428fe1 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5443.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5443.json @@ -1,6 +1,7 @@ { - "title": "Using publicly writable directories is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "Temporary files should not be created in publicly writable directories", + "type": "VULNERABILITY", + "quickfix": "unknown", "code": { "impacts": { "SECURITY": "HIGH" @@ -8,8 +9,13 @@ "attribute": "COMPLETE" }, "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "30min" + }, "tags": [ - "cwe" + "cwe", + "former-hotspot" ], "defaultSeverity": "Critical", "ruleSpecification": "RSPEC-5443", @@ -36,6 +42,5 @@ "STIG ASD_V5R3": [ "V-222567" ] - }, - "quickfix": "unknown" + } } diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5689.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5689.html index eb8e59da7b..dc188af34f 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5689.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5689.html @@ -1,32 +1,20 @@ -

    Disclosure of version information, usually overlooked by developers but disclosed by default by the systems and frameworks in use, can pose a -significant security risk depending on the production environment.

    -

    Once this information is public, attackers can use it to identify potential security holes or vulnerabilities specific to that version.

    -

    Furthermore, if the published version information indicates the use of outdated or unsupported software, it becomes easier for attackers to exploit -known vulnerabilities. They can search for published vulnerabilities related to that version and launch attacks that specifically target those -vulnerabilities.

    -

    Ask Yourself Whether

    -
      -
    • Version information is accessible to end users.
    • -
    • Internal systems do not benefit from timely patch management workflows.
    • -
    -

    There is a risk if you answered yes to any of these questions.

    -

    Recommended Secure Coding Practices

    -

    In general, it is recommended to keep internal technical information within internal systems to control what attackers know about the underlying -architectures. This is known as the "need to know" principle.

    -

    The most effective solution is to remove version information disclosure from what end users can see, such as the "x-powered-by" header. -
    - This can be achieved directly through the web application code, server (nginx, apache) or firewalls.

    -

    Disabling the server signature provides additional protection by reducing the amount of information available to attackers. Note, however, that -this does not provide as much protection as regular updates and patches. -
    - Security by obscurity is the least foolproof solution of all. It should never be the only defense mechanism and should always be combined with other - security measures.

    -

    Sensitive Code Example

    -
    +

    Web application frameworks and servers often disclose version information by default through HTTP headers.

    +

    Why is this an issue?

    +

    Version information disclosed by default through HTTP headers is often overlooked by developers, yet it can pose a security risk. Once this +information is public, attackers can use it to identify potential vulnerabilities specific to that version. This rule raises an issue when version +information is disclosed through HTTP headers such as x-powered-by or Server.

    +

    What is the potential impact?

    +

    If the disclosed version information indicates the use of outdated or unsupported software, it becomes easier for attackers to exploit known +vulnerabilities. They can search for published vulnerabilities related to that version and launch targeted attacks.

    +

    How to fix it

    +

    Do not disclose version information unless necessary. The x-powered-by or Server HTTP headers should not be used.

    +

    Code examples

    +

    Noncompliant code example

    +
     @GetMapping(value = "/example")
     public ResponseEntity<String> example() {
       HttpHeaders responseHeaders = new HttpHeaders();
    -  responseHeaders.set("x-powered-by", "myproduct"); // Sensitive
    +  responseHeaders.set("x-powered-by", "myproduct1.2.3"); // Noncompliant
     
       return new ResponseEntity<String>(
           "example",
    @@ -34,13 +22,24 @@ 

    Sensitive Code Example

    HttpStatus.CREATED); }
    -

    Compliant Solution

    -

    Do not disclose version information unless necessary. The x-powered-by or Server HTTP headers should not be used.

    -

    See

    +

    Compliant solution

    +
    +@GetMapping(value = "/example")
    +public ResponseEntity<String> example() {
    +  return new ResponseEntity<String>(
    +      "example",
    +      HttpStatus.CREATED);
    +}
    +
    +

    Resources

    +

    Documentation

    +

    Standards

    +
      +
    • OWASP - Top 10 2021 Category A5 - Security Misconfiguration
    • OWASP - Top 10 2017 Category A6 - Security Misconfiguration
    • CWE - CWE-200 - Information Exposure
    • diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5689.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5689.json index faa38b8e03..48794797a8 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5689.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5689.json @@ -1,11 +1,11 @@ { - "title": "Disclosing fingerprints from web application technologies is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "Web application technologies should not disclose version information", + "type": "VULNERABILITY", "code": { "impacts": { "SECURITY": "LOW" }, - "attribute": "COMPLETE" + "attribute": "TRUSTWORTHY" }, "status": "ready", "remediation": { @@ -13,12 +13,14 @@ "constantCost": "5min" }, "tags": [ - "cwe" + "cwe", + "former-hotspot" ], "defaultSeverity": "Minor", "ruleSpecification": "RSPEC-5689", "sqKey": "S5689", "scope": "Main", + "quickfix": "unknown", "securityStandards": { "CWE": [ 200 @@ -34,6 +36,5 @@ "7.3.3", "8.3.4" ] - }, - "quickfix": "unknown" + } } diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5693.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5693.html index 8b66b19ecf..89609b7738 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5693.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5693.html @@ -1,58 +1,56 @@ -

      Rejecting requests with significant content length is a good practice to control the network traffic intensity and thus resource consumption in -order to prevent DoS attacks.

      -

      Ask Yourself Whether

      -
        -
      • size limits are not defined for the different resources of the web application.
      • -
      • the web application is not protected by rate limiting features.
      • -
      • the web application infrastructure has limited resources.
      • -
      -

      There is a risk if you answered yes to any of those questions.

      -

      Recommended Secure Coding Practices

      -
        -
      • For most of the features of an application, it is recommended to limit the size of requests to: -
          -
        • lower or equal to 8mb for file uploads.
        • -
        • lower or equal to 2mb for other requests.
        • -
      • -
      -

      It is recommended to customize the rule with the limit values that correspond to the web application.

      -

      Sensitive Code Example

      -

      With default limit value of 8388608 (8MB).

      -

      A 100 MB file is allowed to be uploaded:

      -
      +

      Enforcing a maximum HTTP request content length limits how much data the server must accept per request, which helps control resource use and +reduces the risk of denial-of-service attacks.

      +

      Why is this an issue?

      +

      Accepting HTTP requests without an upper bound on their content length exposes the application to Denial of Service (DoS) attacks. An attacker can +send arbitrarily large requests that exhaust server memory, disk space, or processing capacity before the application can reject them. This rule +detects when no maximum content length is configured, or when the configured limit exceeds the recommended thresholds (8 MB for file uploads, 2 MB for +other requests).

      +

      What is the potential impact?

      +

      Denial of Service

      +

      An attacker who can send oversized HTTP requests can exhaust server resources—memory, CPU threads, or network bandwidth—causing the application to +slow down or become completely unavailable. Even a single large upload can tie up a worker process and prevent other users from being served.

      +

      How to fix it in Spring

      +

      Limit the upload size by setting a maximum value on the multipart resolver or multipart configuration factory.

      +

      Code examples

      +

      Noncompliant code example

      +
       @Bean(name = "multipartResolver")
       public CommonsMultipartResolver multipartResolver() {
         CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
      -  multipartResolver.setMaxUploadSize(104857600); // Sensitive (100MB)
      +  multipartResolver.setMaxUploadSize(104857600); // Noncompliant
         return multipartResolver;
       }
       
       @Bean(name = "multipartResolver")
       public CommonsMultipartResolver multipartResolver() {
      -  CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); // Sensitive, by default if maxUploadSize property is not defined, there is no limit and thus it's insecure
      +  CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); // Noncompliant
         return multipartResolver;
       }
       
       @Bean
       public MultipartConfigElement multipartConfigElement() {
      -  MultipartConfigFactory factory = new MultipartConfigFactory(); // Sensitive, no limit by default
      +  MultipartConfigFactory factory = new MultipartConfigFactory(); // Noncompliant
         return factory.createMultipartConfig();
       }
       
      -

      Compliant Solution

      -

      File upload size is limited to 8 MB:

      -
      +

      Compliant solution

      +
       @Bean(name = "multipartResolver")
       public CommonsMultipartResolver multipartResolver() {
      -  multipartResolver.setMaxUploadSize(8388608); // Compliant (8 MB)
      +  CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
      +  multipartResolver.setMaxUploadSize(8388608);
         return multipartResolver;
       }
       
      -

      See

      +

      Resources

      +

      Articles & blog posts

      + +

      Standards

      • OWASP - Top 10 2021 Category A5 - Security Misconfiguration
      • -
      • Owasp Cheat Sheet - Owasp Denial of Service - Cheat Sheet
      • OWASP - Top 10 2017 Category A6 - Security Misconfiguration
      • CWE - CWE-770 - Allocation of Resources Without Limits or Throttling
      • diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5693.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5693.json index e97d8c1345..cbf84b14dc 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5693.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5693.json @@ -1,6 +1,6 @@ { - "title": "Allowing requests with excessive content length is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "HTTP request content length should be limited", + "type": "VULNERABILITY", "code": { "impacts": { "SECURITY": "MEDIUM" @@ -12,8 +12,10 @@ "func": "Constant\/Issue", "constantCost": "5min" }, + "quickfix": "unknown", "tags": [ - "cwe" + "cwe", + "former-hotspot" ], "defaultSeverity": "Major", "ruleSpecification": "RSPEC-5693", @@ -40,6 +42,5 @@ "12.1.1", "12.1.3" ] - }, - "quickfix": "unknown" + } } diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5804.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5804.html index 979b9c63e2..57510f94e2 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5804.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5804.html @@ -1,101 +1,93 @@ -

        User enumeration refers to the ability to guess existing usernames in a web application database. This can happen, for example, when using -"sign-in/sign-on/forgot password" functionalities of a website.

        -

        When an user tries to "sign-in" to a website with an incorrect username/login, the web application should not disclose that the username doesn’t -exist with a message similar to "this username is incorrect", instead a generic message should be used like "bad credentials", this way it’s not -possible to guess whether the username or password was incorrect during the authentication.

        -

        If a user-management feature discloses information about the existence of a username, attackers can use brute force attacks to retrieve a large -amount of valid usernames that will impact the privacy of corresponding users and facilitate other attacks (phishing, password guessing etc …​).

        -

        Ask Yourself Whether

        -
          -
        • The application discloses that a username exists in its database: most of the time it’s possible to avoid this kind of leak except for the - "registration/sign-on" part of a website because in this case the user must choose a valid username (not already taken by another user).
        • -
        • There is no rate limiting and CAPTCHA protection in place for requests involving a username.
        • -
        -

        There is a risk if you answered yes to any of those questions.

        -

        Recommended Secure Coding Practices

        -

        When a user performs a request involving a username, it should not be possible to spot differences between a valid and incorrect username:

        -
          -
        • Error messages should be generic and not disclose if the username is valid or not.
        • -
        • The response time must be similar for a valid username or not.
        • -
        • CAPTCHA and other rate limiting solutions should be implemented.
        • -
        -

        Sensitive Code Example

        -

        In a Spring-security web application the username leaks when:

        -
          -
        • The string used as argument of loadUserByUsername method is used in an exception message:
        • -
        -
        +

        Authentication mechanisms should not reveal whether a username exists in the system.

        +

        Why is this an issue?

        +

        User enumeration occurs when an application discloses whether a given username exists in its database, for example through sign-in, sign-on, or +forgot-password functionalities. When error messages or exception handling differ depending on whether a username is valid, attackers can use +brute-force techniques to harvest valid usernames. This facilitates further attacks such as credential stuffing, phishing, and targeted password +guessing, and impacts the privacy of the affected users.

        +

        What is the potential impact?

        +

        If an attacker can enumerate valid usernames, it significantly increases the success rate of credential stuffing or social engineering. They can +launch targeted credential-stuffing or password-guessing campaigns against confirmed accounts, and use the harvested usernames in phishing schemes. +This also degrades user privacy, since the mere existence of an account can reveal personal information.

        +

        How to fix it in Spring

        +

        Code examples

        +

        The following code leaks information about the existence of usernames by using distinct error messages, throwing +UsernameNotFoundException outside the loadUserByUsername method, or disabling HideUserNotFoundExceptions.

        +

        Noncompliant code example

        +
         public String authenticate(String username, String password) {
        -  // ....
        +
           MyUserDetailsService s1 = new MyUserDetailsService();
           MyUserPrincipal u1 = s1.loadUserByUsername(username);
         
           if(u1 == null) {
        -    throw new BadCredentialsException(username+" doesn't exist in our database"); // Sensitive
        +    throw new BadCredentialsException(username+" doesn't exist in our database"); // Noncompliant
           }
        -  // ....
        +
         }
        -
        - -
        -public String authenticate(String username, String password) {
        -  // ....
        +
        +public String authenticate2(String username, String password) {
        +
        +  MyUserDetailsService s2 = new MyUserDetailsService();
        +  MyUserPrincipal user = s2.loadUserByUsername(username);
        +
           if(user == null) {
        -      throw new UsernameNotFoundException("user not found"); // Sensitive
        +      throw new UsernameNotFoundException("user not found"); // Noncompliant
           }
        -  // ....
        +
        +}
        +
        +public void configure() {
        +  DaoAuthenticationProvider daoauth = new DaoAuthenticationProvider();
        +  daoauth.setUserDetailsService(new MyUserDetailsService());
        +  daoauth.setPasswordEncoder(new BCryptPasswordEncoder());
        +  daoauth.setHideUserNotFoundExceptions(false); // Noncompliant
        +  builder.authenticationProvider(daoauth);
         }
         
        - -
        -DaoAuthenticationProvider daoauth = new DaoAuthenticationProvider();
        -daoauth.setUserDetailsService(new MyUserDetailsService());
        -daoauth.setPasswordEncoder(new BCryptPasswordEncoder());
        -daoauth.setHideUserNotFoundExceptions(false); // Sensitive
        -builder.authenticationProvider(daoauth);
        -
        -

        Compliant Solution

        -

        In a Spring-security web application:

        -
          -
        • the same message should be used regardless of whether it is the wrong user or password:
        • -
        -
        -public String authenticate(String username, String password) throws AuthenticationException {
        +

        Compliant solution

        +
        +public boolean authenticate(String username, String password) throws AuthenticationException {
        +  verifyCredentials(username, password);
        +  return true;
        +}
        +
        +private void verifyCredentials(String username, String password) throws AuthenticationException {
           Details user = null;
           try {
             user = loadUserByUsername(username);
           } catch (UsernameNotFoundException | DataAccessException e) {
        -    // Hide this exception reason to not disclose that the username doesn't exist
        +    // Hide the reason to avoid disclosing user existence.
           }
           if (user == null || !user.isPasswordCorrect(password)) {
        -     // User should not be able to guess if the bad credentials message is related to the username or the password
             throw new BadCredentialsException("Bad credentials");
           }
         }
        +
        +public void configure() {
        +  DaoAuthenticationProvider daoauth = new DaoAuthenticationProvider();
        +  daoauth.setUserDetailsService(new MyUserDetailsService());
        +  daoauth.setPasswordEncoder(new BCryptPasswordEncoder());
        +  daoauth.setHideUserNotFoundExceptions(true);
        +  builder.authenticationProvider(daoauth);
        +}
         
        +

        Resources

        +

        Documentation

        • HideUserNotFoundExceptions should be set to true:
        • + href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/core/userdetails/UserDetailsService.html">Spring + Security - UserDetailsService +
        • Spring Security - UsernameNotFoundException
        • +
        • Spring Security - setHideUserNotFoundExceptions
        -
        -DaoAuthenticationProvider daoauth = new DaoAuthenticationProvider();
        -daoauth.setUserDetailsService(new MyUserDetailsService());
        -daoauth.setPasswordEncoder(new BCryptPasswordEncoder());
        -daoauth.setHideUserNotFoundExceptions(true); // Compliant
        -builder.authenticationProvider(daoauth);
        -
        -

        See

        +

        Standards

        diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5804.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5804.json index cdcea85323..6d705ed07e 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5804.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S5804.json @@ -1,6 +1,6 @@ { - "title": "Allowing user enumeration is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "Authentication mechanisms should not permit user enumeration.", + "type": "VULNERABILITY", "code": { "impacts": { "SECURITY": "MEDIUM" @@ -12,9 +12,11 @@ "func": "Constant\/Issue", "constantCost": "10min" }, + "quickfix": "unknown", "tags": [ "cwe", - "spring" + "spring", + "former-hotspot" ], "defaultSeverity": "Major", "ruleSpecification": "RSPEC-5804", @@ -22,7 +24,8 @@ "scope": "Main", "securityStandards": { "CWE": [ - 200 + 200, + 203 ], "OWASP": [ "A2" @@ -41,6 +44,5 @@ "7.3.3", "8.3.4" ] - }, - "quickfix": "unknown" + } } diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6263.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6263.html index e22cd8a21c..e7ff11e8e4 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6263.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6263.html @@ -1,38 +1,47 @@ -

        In AWS, long-term access keys will be valid until you manually revoke them. This makes them highly sensitive as any exposure can have serious -consequences and should be used with care.

        -

        This rule will trigger when encountering an instantiation of com.amazonaws.auth.BasicAWSCredentials.

        -

        Ask Yourself Whether

        -
          -
        • The access key is used directly in an application or AWS CLI script running on an Amazon EC2 instance.
        • -
        • Cross-account access is needed.
        • -
        • The access keys need to be embedded within a mobile application.
        • -
        • Existing identity providers (SAML 2.0, on-premises identity store) already exists.
        • -
        -

        For more information, see Use IAM roles -instead of long-term access keys.

        -

        There is a risk if you answered yes to any of those questions.

        -

        Recommended Secure Coding Practices

        -

        Consider using IAM roles or other features of the AWS Security Token Service that provide temporary credentials, limiting the risks.

        -

        Sensitive Code Example

        -
        +

        In AWS, long-term access keys provide persistent programmatic access to AWS services but carry a higher risk than temporary credentials because +they do not expire automatically.

        +

        Why is this an issue?

        +

        This rule detects uses of com.amazonaws.auth.BasicAWSCredentials, a class that creates long-term credential objects. Unlike temporary +credentials, long-term access keys remain valid indefinitely until manually revoked, making them a persistent risk if exposed. Using long-term keys in +application code increases the risk of accidental exposure and makes credential rotation harder to enforce.

        +

        What is the potential impact?

        +

        If a long-term access key is exposed through source code, configuration files, or logs, an attacker gains persistent access to AWS resources until +the key is manually revoked. This can lead to unauthorized access to sensitive data, privilege escalation, or significant financial costs from +resource abuse.

        +

        How to fix it

        +

        The preferred approach is to avoid static credentials entirely by using IAM roles, which provide short-lived credentials automatically. On EC2, +ECS, or Lambda, assign an IAM role to the instance or task — the AWS SDK picks up the credentials without any code changes via the default credential +provider chain.

        +

        Where temporary credentials must be obtained programmatically, use AWS +STS to request short-lived session credentials.

        +

        Code examples

        +

        Noncompliant code example

        +
         import com.amazonaws.auth.AWSCredentials;
         import com.amazonaws.auth.BasicAWSCredentials;
         // ...
         
        -AWSCredentials awsCredentials = new BasicAWSCredentials(accessKeyId, secretAccessKey);
        +AWSCredentials awsCredentials = new BasicAWSCredentials(accessKeyId, secretAccessKey); // Noncompliant
         
        -

        Compliant Solution

        -

        Example for AWS STS (see Getting Temporary Credentials -with AWS STS).

        -
        +

        Compliant solution

        +
        +// session_creds obtained via an STS AssumeRole call
         BasicSessionCredentials sessionCredentials = new BasicSessionCredentials(
            session_creds.getAccessKeyId(),
            session_creds.getSecretAccessKey(),
            session_creds.getSessionToken());
         
        -

        See

        +

        Resources

        +

        Documentation

        + +

        Standards

        diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6263.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6263.json index 34b96578b6..e64158fd25 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6263.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6263.json @@ -1,6 +1,6 @@ { - "title": "Using long-term access keys is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "Long-term AWS access keys should not be used", + "type": "VULNERABILITY", "code": { "impacts": { "SECURITY": "MEDIUM" @@ -13,7 +13,8 @@ "constantCost": "1h" }, "tags": [ - "aws" + "aws", + "former-hotspot" ], "defaultSeverity": "Major", "ruleSpecification": "RSPEC-6263", diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6288.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6288.html index 16fce9107c..086637d6d1 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6288.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6288.html @@ -1,44 +1,55 @@ -

        Android KeyStore is a secure container for storing key materials, in particular it prevents key materials extraction, i.e. when the application -process is compromised, the attacker cannot extract keys but may still be able to use them. It’s possible to enable an Android security feature, user -authentication, to restrict usage of keys to only authenticated users. The lock screen has to be unlocked with defined credentials -(pattern/PIN/password, biometric).

        -

        Ask Yourself Whether

        -
          -
        • The application requires prohibiting the use of keys in case of compromise of the application process.
        • -
        • The key material is used in the context of a highly sensitive application like a e-banking mobile app.
        • -
        -

        There is a risk if you answered yes to any of those questions.

        -

        Recommended Secure Coding Practices

        -

        It’s recommended to enable user authentication (by setting setUserAuthenticationRequired to true during key generation) -to use keys for a limited duration of time (by setting appropriate values to setUserAuthenticationValidityDurationSeconds), after which -the user must re-authenticate.

        -

        Sensitive Code Example

        -

        Any user can use the key:

        -
        +

        Android KeyStore is a secure container for storing cryptographic key material. It prevents key extraction: even if the application process is +compromised, an attacker cannot extract keys from the KeyStore, though they may still use them to perform cryptographic operations. Enabling user +authentication restricts key usage to authenticated users only, requiring the lock screen to be unlocked with a defined credential (PIN, password, +pattern, or biometric).

        +

        Why is this an issue?

        +

        When cryptographic keys are configured without requiring user authentication, any code running within the application process can use those keys +freely. On Android, this happens when a KeyGenParameterSpec.Builder is built without calling +setUserAuthenticationRequired(true).

        +

        What is the potential impact?

        +

        If the application process is compromised, an attacker can use unprotected keys to decrypt sensitive data, forge digital signatures, or impersonate +the user without their knowledge. Although the key material itself cannot be extracted from the secure storage, it can still be used to perform +cryptographic operations on behalf of the attacker.

        +

        How to fix it

        +

        Call setUserAuthenticationRequired(true) on the KeyGenParameterSpec.Builder to restrict key use to authenticated users +only. The lock screen must be unlocked with a defined credential (PIN, password, pattern, or biometric) before the key can be used. Use +setUserAuthenticationParameters to configure the authentication timeout and the accepted credential types; after the timeout expires, the +user must re-authenticate.

        +

        Code examples

        +

        The following code creates a cryptographic key without requiring user authentication, allowing any code running in the application process to use +it.

        +

        Noncompliant code example

        +
         KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
         
        -KeyGenParameterSpec builder = new KeyGenParameterSpec.Builder("test_secret_key_noncompliant", KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) // Noncompliant
        +KeyGenParameterSpec builder = new KeyGenParameterSpec.Builder("example-key", KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) // Noncompliant
             .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
             .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
             .build();
         
         keyGenerator.init(builder);
         
        -

        Compliant Solution

        -

        The use of the key is limited to authenticated users (for a duration of time defined to 60 seconds):

        -
        +

        Compliant solution

        +
         KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
         
        -KeyGenParameterSpec builder = new KeyGenParameterSpec.Builder("test_secret_key", KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
        +KeyGenParameterSpec builder = new KeyGenParameterSpec.Builder("example-key", KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
             .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
             .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
             .setUserAuthenticationRequired(true)
        -    .setUserAuthenticationParameters (60, KeyProperties.AUTH_DEVICE_CREDENTIAL)
        +    .setUserAuthenticationParameters (60, KeyProperties.AUTH_DEVICE_CREDENTIAL) // 60 seconds
             .build();
         
        -keyGenerator.init(builder)
        +keyGenerator.init(builder);
         
        -

        See

        +

        Resources

        +

        Documentation

        + +

        Standards

        diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6288.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6288.json index 7f3b7bd8aa..f1e3d80ff1 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6288.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6288.json @@ -1,6 +1,6 @@ { - "title": "Authorizing non-authenticated users to use keys in the Android KeyStore is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "Android KeyStore keys should require user authentication", + "type": "VULNERABILITY", "code": { "impacts": { "SECURITY": "MEDIUM" @@ -14,7 +14,8 @@ }, "tags": [ "cwe", - "android" + "android", + "former-hotspot" ], "defaultSeverity": "Major", "ruleSpecification": "RSPEC-6288", diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6293.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6293.html index 63ab9570a4..114684655d 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6293.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6293.html @@ -1,35 +1,37 @@ -

        Android comes with Android KeyStore, a secure container for storing key materials. It’s possible to define certain keys to be unlocked when users -authenticate using biometric credentials. This way, even if the application process is compromised, the attacker cannot access keys, as presence of -the authorized user is required.

        -

        These keys can be used, to encrypt, sign or create a message authentication code (MAC) as proof that the authentication result has not been -tampered with. This protection defeats the scenario where an attacker with physical access to the device would try to hook into the application -process and call the onAuthenticationSucceeded method directly. Therefore he would be unable to extract the sensitive data or to perform -the critical operations protected by the biometric authentication.

        -

        Ask Yourself Whether

        -

        The application contains:

        -
          -
        • Cryptographic keys / sensitive information that need to be protected using biometric authentication.
        • -
        -

        There is a risk if you answered yes to this question.

        -

        Recommended Secure Coding Practices

        -

        It’s recommended to tie the biometric authentication to a cryptographic operation by using a CryptoObject during authentication.

        -

        Sensitive Code Example

        -

        A CryptoObject is not used during authentication:

        -
        +

        Biometric authentication on Android should be tied to a cryptographic operation to prevent attackers from bypassing the authentication result.

        +

        Why is this an issue?

        +

        Android KeyStore allows defining keys that require biometric authentication before use. When BiometricPrompt.authenticate is called +without a CryptoObject, the authentication result can be tampered with. An attacker with physical access to the device could hook into +the application process and call onAuthenticationSucceeded directly, bypassing the biometric check entirely.

        +

        What is the potential impact?

        +

        Authentication bypass

        +

        If biometric authentication is not tied to a cryptographic operation, an attacker with physical access to the device can bypass the authentication. +This could allow unauthorized access to sensitive data or critical operations that the biometric check was meant to protect.

        +

        How to fix it

        +

        Code examples

        +

        A CryptoObject should be passed to the authenticate method to bind the biometric authentication to a cryptographic +operation.

        +

        Noncompliant code example

        +
         // ...
         BiometricPrompt biometricPrompt = new BiometricPrompt(activity, executor, callback);
         // ...
         biometricPrompt.authenticate(promptInfo); // Noncompliant
         
        -

        Compliant Solution

        -

        A CryptoObject is used during authentication:

        -
        +

        Compliant solution

        +
         // ...
         BiometricPrompt biometricPrompt = new BiometricPrompt(activity, executor, callback);
         // ...
        -biometricPrompt.authenticate(promptInfo, new BiometricPrompt.CryptoObject(cipher)); // Compliant
        +biometricPrompt.authenticate(promptInfo, new BiometricPrompt.CryptoObject(cipher));
         
        -

        See

        +

        Resources

        +

        Documentation

        + +

        Standards

        diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6293.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6293.json index 34244745d9..8f9d85358d 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6293.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6293.json @@ -1,6 +1,6 @@ { - "title": "Using biometric authentication without a cryptographic solution is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "Biometric authentication should be cryptographically bound", + "type": "VULNERABILITY", "code": { "impacts": { "SECURITY": "MEDIUM" @@ -14,7 +14,8 @@ }, "tags": [ "cwe", - "android" + "android", + "former-hotspot" ], "defaultSeverity": "Major", "ruleSpecification": "RSPEC-6293", @@ -22,7 +23,7 @@ "scope": "Main", "securityStandards": { "CWE": [ - 287 + 1390 ], "OWASP Mobile": [ "M4" diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6363.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6363.html index 2a0a0a390e..26731d4bf7 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6363.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6363.html @@ -1,40 +1,77 @@ -

        Granting file access to WebViews, particularly through the file:// scheme, introduces a risk of local file inclusion vulnerabilities. -The severity of this risk depends heavily on the specific settings configured for the WebView. Overly permissive settings can allow malicious scripts -to access a wide range of local files, potentially exposing sensitive data such as Personally Identifiable Information (PII) or private application -data, leading to data breaches and other security compromises.

        -

        Ask Yourself Whether

        -
          -
        • You open files that may be created or altered by external sources.
        • -
        • You open arbitrary URLs from external sources.
        • -
        -

        There is a risk if you answered yes to any of these questions.

        -

        Recommended Secure Coding Practices

        -

        Avoid opening file:// URLs from external sources in WebView components. If your application accepts arbitrary URLs from external -sources, do not enable this functionality.

        -

        On Android, it is recommended to use androidx.webkit.WebViewAssetLoader to access files, including assets and resources, via a custom, -controllable scheme.

        -

        On iOS, it is recommended to use Bundles to access local files, keeping access limited a controlled subset using the -allowingReadAccessTo parameter of the loadFileURL method. If allowFileAccessFromFileURLs and -allowUniversalAccessFromFileURLs are not enabled, it is not possible to access files outside the intended directory. It is also possible -to create a custom scheme to access local files, but this is more complex and might lead to unintended security issues.

        -

        For enhanced security, ensure that the options to load file:// URLs are explicitly set to false.

        -

        Sensitive Code Example

        -
        +

        Granting file access to WebViews, particularly through the file:// scheme, can expose sensitive local files to malicious scripts.

        +

        Why is this an issue?

        +

        WebViews can be configured to allow scripts to access local files through the file:// scheme. When file access settings are enabled, +JavaScript running within the WebView can read files from the device’s local file system, including sensitive application data.

        +

        Settings such as setAllowFileAccess, setAllowContentAccess, allowFileAccessFromFileURLs, and +allowUniversalAccessFromFileURLs control this behavior on Android.

        +

        What is the potential impact?

        +

        Data exposure

        +

        If a malicious script is loaded in a WebView with file access enabled, it can read arbitrary files from the device’s local file system. This +includes sensitive application data, user credentials, authentication tokens, and Personally Identifiable Information (PII) stored in local files.

        +

        Loss of confidentiality

        +

        Exposed data can be exfiltrated to attacker-controlled servers, leading to account compromise, identity theft, and data breaches.

        +

        How to fix it

        +

        Use WebViewAssetLoader to load local files instead of directly accessing them via file:// URLs. This approach serves +assets over a secure https://appassets.androidplatform.net URL, effectively isolating the WebView from the local file system.

        +

        The file access settings are disabled by default in modern Android versions. To prevent possible security issues in +Build.VERSION_CODES.Q and earlier, it is still recommended to explicitly set those values to false.

        +

        Code examples

        +

        Noncompliant code example

        +
         import android.webkit.WebView;
        +import android.webkit.WebViewClient;
         
         WebView webView = (WebView) findViewById(R.id.webview);
        -webView.getSettings().setAllowFileAccess(true); // Sensitive
        -webView.getSettings().setAllowContentAccess(true); // Sensitive
        +webView.setWebViewClient(new WebViewClient());
        +webView.getSettings().setAllowFileAccess(true); // Noncompliant
        +webView.getSettings().setAllowFileAccessFromFileURLs(true); // Noncompliant
        +webView.getSettings().setAllowUniversalAccessFromFileURLs(true); // Noncompliant
        +webView.getSettings().setAllowContentAccess(true); // Noncompliant
        +webView.loadUrl("file:///android_asset/example.html");
         
        -

        Compliant Solution

        -
        +

        Compliant solution

        +
        +import android.net.Uri;
        +import android.webkit.WebResourceRequest;
        +import android.webkit.WebResourceResponse;
         import android.webkit.WebView;
        +import android.webkit.WebViewClient;
        +import androidx.annotation.RequiresApi;
        +import androidx.webkit.WebViewAssetLoader;
         
         WebView webView = (WebView) findViewById(R.id.webview);
        +WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
        +    .addPathHandler("/assets/", new WebViewAssetLoader.AssetsPathHandler(this))
        +    .build();
        +
        +webView.setWebViewClient(new WebViewClient() {
        +    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
        +    @Override
        +    public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
        +        return assetLoader.shouldInterceptRequest(request.getUrl());
        +    }
        +
        +    @SuppressWarnings("deprecation")
        +    @Override
        +    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
        +        return assetLoader.shouldInterceptRequest(Uri.parse(url));
        +    }
        +});
        +
         webView.getSettings().setAllowFileAccess(false);
        +webView.getSettings().setAllowFileAccessFromFileURLs(false);
        +webView.getSettings().setAllowUniversalAccessFromFileURLs(false);
         webView.getSettings().setAllowContentAccess(false);
        +
        +webView.loadUrl("https://appassets.androidplatform.net/assets/example.html");
         
        -

        See

        +

        Resources

        +

        Documentation

        + +

        Standards

        diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6363.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6363.json index 790bcdd60e..05309e8d7c 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6363.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6363.json @@ -1,6 +1,6 @@ { - "title": "Enabling file access for WebViews is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "WebViews should not allow unrestricted file access", + "type": "VULNERABILITY", "code": { "impacts": { "SECURITY": "MEDIUM" @@ -14,7 +14,8 @@ }, "tags": [ "cwe", - "android" + "android", + "former-hotspot" ], "defaultSeverity": "Major", "ruleSpecification": "RSPEC-6363", diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7409.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7409.html index 983dba7437..dfc9747a5f 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7409.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7409.html @@ -1,33 +1,21 @@ -

        Using JavaScript interfaces in WebViews to expose Java objects is unsafe. Doing so allows JavaScript to invoke Java methods, potentially giving -attackers access to data or sensitive app functionality. WebViews might include untrusted sources such as third-party iframes, making this -functionality particularly risky. As JavaScript interfaces are passed to every frame in the WebView, those iframes are also able to access the exposed -Java object.

        -

        Ask Yourself Whether

        -
          -
        • The content in the WebView is fully trusted and secure.
        • -
        • Potentially untrusted iframes could be loaded in the WebView.
        • -
        • The JavaScript interface has to be exposed for the entire lifecycle of the WebView.
        • -
        • The exposed Java object might be called by untrusted sources.
        • -
        -

        There is a risk if you answered yes to any of these questions.

        -

        Recommended Secure Coding Practices

        -

        Disable JavaScript

        -

        If it is possible to disable JavaScript in the WebView, this is the most secure option. By default, JavaScript is disabled in a WebView, so -webSettings.setJavaScriptEnabled(false) does not need to be explicitly called. Of course, sometimes it is necessary to enable JavaScript, -in which case the following recommendations should be considered.

        -

        Remove JavaScript interface when loading untrusted content

        -

        JavaScript interfaces can be removed at a later point. It is recommended to remove the JavaScript interface when it is no longer needed. If it is -needed for a longer time, consider removing it before loading untrusted content. This can be done by calling -webView.removeJavascriptInterface("interfaceName").

        -

        A good place to do this is inside the shouldInterceptRequest method of a WebViewClient, where you can check the URL or -resource being loaded and remove the interface if the content is untrusted.

        -

        Alternative methods to implement native bridges

        -

        If a native bridge has to be added to the WebView, and it is impossible to remove it at a later point, consider using an alternative method that -offers more control over the communication flow. WebViewCompat.postWebMessage/WebViewCompat.addWebMessageListener and -WebMessagePort.postMessage offer more ways to validate incoming and outgoing messages, such as by being able to restrict the origins that -can send messages to the JavaScript bridge.

        -

        Sensitive Code Example

        -
        +

        WebView JavaScript interfaces expose native application methods to JavaScript code running in an embedded web view. If the web view loads untrusted +content, any script — including attacker-controlled code — can call those native methods directly.

        +

        Why is this an issue?

        +

        Once a JavaScript interface is registered on a web view, the exposed native object is accessible to all JavaScript running in that web view, +including scripts in untrusted third-party iframes. Web views may load content from sources that are not fully trusted, and JavaScript interfaces are +propagated to every frame, not just the top-level page. An attacker who can inject or control JavaScript in any frame can therefore call the exposed +native methods directly.

        +

        What is the potential impact?

        +

        Unauthorized access to sensitive data or functionality

        +

        An attacker who controls JavaScript in the WebView — for example, through a malicious third-party iframe embedded in an otherwise legitimate page — +can invoke exposed native methods without restriction. Depending on what the methods expose, this can lead to unauthorized access to sensitive user +data, execution of privileged application functionality, or full compromise of the application’s security model.

        +

        How to fix it

        +

        Code examples

        +

        The following code is vulnerable because it registers a native interface that is accessible to all JavaScript running in the WebView, including +JavaScript from untrusted sources such as third-party iframes.

        +

        Noncompliant code example

        +
         public class ExampleActivity extends AppCompatActivity {
             @Override
             protected void onCreate(Bundle savedInstanceState) {
        @@ -35,7 +23,7 @@ 

        Sensitive Code Example

        WebView webView = new WebView(this); webView.getSettings().setJavaScriptEnabled(true); - webView.addJavascriptInterface(new JavaScriptBridge(), "androidBridge"); // Sensitive + webView.addJavascriptInterface(new JavaScriptBridge(), "androidBridge"); // Noncompliant } public static class JavaScriptBridge { @@ -46,40 +34,8 @@

        Sensitive Code Example

        } }
        -

        Compliant Solution

        -

        The most secure option is to disable JavaScript entirely. {rule:java:S6362} further explains why it should not be enabled unless absolutely -necessary.

        -
        -public class ExampleActivity extends AppCompatActivity {
        -    @Override
        -    protected void onCreate(Bundle savedInstanceState) {
        -        super.onCreate(savedInstanceState);
        -
        -        WebView webView = new WebView(this);
        -        webView.getSettings().setJavaScriptEnabled(false);
        -    }
        -}
        -
        -

        If possible, remove the JavaScript interface after it is no longer needed, or before loading any untrusted content.

        -
        -public class ExampleActivity extends AppCompatActivity {
        -    @Override
        -    protected void onCreate(Bundle savedInstanceState) {
        -        super.onCreate(savedInstanceState);
        -
        -        WebView webView = new WebView(this);
        -        webView.getSettings().setJavaScriptEnabled(true);
        -
        -        webView.addJavascriptInterface(new JavaScriptBridge(), "androidBridge");
        -
        -        // Sometime later, before unsafe content is loaded, remove the JavaScript interface
        -        webView.removeJavascriptInterface("androidBridge");
        -    }
        -}
        -
        -

        If a JavaScript bridge must be used, consider using WebViewCompat.addWebMessageListener instead. This allows you to restrict the -origins that can send messages to the JavaScript bridge.

        -
        +

        Compliant solution

        +
         public class ExampleActivity extends AppCompatActivity {
             private static final Set<String> ALLOWED_ORIGINS = Collections.singleton("https://example.com");
         
        @@ -110,17 +66,36 @@ 

        Compliant Solution

        } }
        -

        See

        + + + + + + + +
        NoteIf the interface cannot be replaced immediately, it can be removed before loading untrusted content.
        +
        +webView.addJavascriptInterface(new JavaScriptBridge(), "androidBridge");
        +// ...
        +// Remove the interface before loading untrusted content
        +webView.removeJavascriptInterface("androidBridge");
        +webView.loadUrl("https://untrusted.example.com");
        +
        +

        Resources

        +

        Documentation

        +

        Standards

        +

        Related rules

          diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7409.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7409.json index 0c3692daf8..f6ed21e42a 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7409.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7409.json @@ -1,6 +1,6 @@ { - "title": "Exposing native code through JavaScript interfaces is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "Native methods should not be exposed to untrusted WebView content", + "type": "VULNERABILITY", "status": "ready", "remediation": { "func": "Constant\/Issue", @@ -8,7 +8,8 @@ }, "tags": [ "cwe", - "android" + "android", + "former-hotspot" ], "defaultSeverity": "Major", "ruleSpecification": "RSPEC-7409", @@ -26,7 +27,7 @@ "A5" ], "CWE": [ - 79 + 749 ] }, "quickfix": "unknown", diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7435.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7435.html index 74f66ae889..18f3517956 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7435.html +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7435.html @@ -1,51 +1,45 @@ -

          Mobile devices expose unique identifiers that can be used to identify users across applications or devices. These identifiers put user privacy at -risk, as they might allow the tracking of user activity without consent, while making it difficult or impossible for users to reset them.

          -

          Privacy violations can cause apps to be removed from app stores and can result in legal action or loss of trust from users.

          -

          Ask Yourself Whether

          -
            -
          • The identifier is used to track users between applications or devices.
          • -
          • The identifier cannot be easily reset by the user.
          • -
          • The identifier is connected to personally identifiable information.
          • -
          • The identifier is linked to the device hardware (MAC address, IMEI, etc).
          • -
          -

          There is a risk if you answer yes to any of these questions.

          -

          Recommended Secure Coding Practices

          -
            -
          • Whenever possible, use identifiers that users can easily reset.
          • -
          • Don’t link identifiers to personally identifiable information without collecting users' explicit consent.
          • -
          • Avoid using identifiers that are linked to the device hardware (MAC address, IMEI, etc).
          • -
          • Only use the Advertising ID for user profiling or ads use cases.
          • -
          -

          For ads use cases, use the Advertising ID provided by the platform. This identifier is designed to be reset by the user and has an associated -Personalized Ads flag.

          -

          For non-ads use cases, the most privacy-friendly identifiers that can be used are:

          -
            -
          • Firebase installation ID (FID)
          • -
          • A privately stored GUID generated by the app
          • -
          -

          Sensitive Code Example

          +

          Mobile devices expose unique identifiers that can be used to track users across applications without their consent.

          +

          Why is this an issue?

          +

          Mobile platforms provide access to device identifiers such as the Android ID or the iOS Identifier for Vendors. These identifiers are persistent +across app sessions and can be used to track user activity across applications and devices. This rule raises an issue when code accesses such +persistent device identifiers.

          +

          What is the potential impact?

          +

          Using persistent unique identifiers without user consent can lead to privacy violations. Users may be tracked across applications or devices +without their knowledge, and the identifiers may be linked to personally identifiable information. Privacy violations can cause apps to be removed +from app stores and can result in legal action or loss of trust from users.

          +

          How to fix it

          +

          Code examples

          +

          Instead of using a persistent device identifier, generate a random UUID. The UUID should be persisted in secure local storage (e.g. +SharedPreferences, Keychain) so the same value is reused across sessions. This approach gives users control over their privacy, as the identifier is +reset when the app is reinstalled.

          +

          Noncompliant code example

          -String uid = Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID); // Sensitive
          +String uid = Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID); // Noncompliant
           User user = new User(
               uid,
               "John",
          -    "Doe",
          +    "Doe"
           );
           
          -

          Compliant Solution

          +

          Compliant solution

           String uid = UUID.randomUUID().toString();
           User user = new User(
               uid,
               "John",
          -    "Doe",
          +    "Doe"
           );
           
          -

          See

          +

          Resources

          +

          Documentation

          +

          Standards

          + diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7435.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7435.json index 34e957865e..f63ccada4f 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7435.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S7435.json @@ -1,13 +1,16 @@ { - "title": "Processing persistent unique identifiers is security-sensitive", - "type": "SECURITY_HOTSPOT", + "title": "Avoid using persistent unique identifiers", + "type": "VULNERABILITY", "status": "ready", "remediation": { "func": "Constant\/Issue", "constantCost": "5min" }, "tags": [ - "android" + "android", + "ios", + "cwe", + "former-hotspot" ], "defaultSeverity": "Minor", "ruleSpecification": "RSPEC-7435", diff --git a/sonarpedia.json b/sonarpedia.json index 2e806aecbf..6063f6d862 100644 --- a/sonarpedia.json +++ b/sonarpedia.json @@ -3,7 +3,7 @@ "languages": [ "JAVA" ], - "latest-update": "2026-04-09T13:46:03.313330Z", + "latest-update": "2026-04-24T11:47:20.318767361Z", "options": { "no-language-in-filenames": true, "preserve-filenames": false