Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions .gstack/security-reports/20260519-163613.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
{
"version": "2.0.0",
"date": "2026-05-19T16:30:00Z",
"mode": "daily",
"scope": "full",
"diff_mode": false,
"phases_run": [0, 1, 2, 3, 5, 6, 9, 12, 13, 14],
"attack_surface": {
"code": {
"public_endpoints": 4,
"authenticated": 1,
"admin": 0,
"api": 5,
"uploads": 0,
"integrations": 1,
"background_jobs": 0,
"websockets": 0
},
"infrastructure": {
"ci_workflows": 0,
"webhook_receivers": 0,
"container_configs": 4,
"iac_configs": 0,
"deploy_targets": 0,
"secret_management": "environment-variables"
}
},
"findings": [
{
"id": 1,
"severity": "MEDIUM",
"confidence": 9,
"status": "VERIFIED",
"phase": 5,
"phase_name": "Infrastructure Shadow Surface",
"category": "Infrastructure",
"fingerprint": "sha256-docker-root-user-missing",
"title": "Dockerfiles run as root",
"file": "*/Dockerfile",
"line": 0,
"description": "All workshop Dockerfiles are missing the USER directive, causing containers to run as root.",
"exploit_scenario": "If attacker compromises the application via RCE, they gain root access inside container, enabling container escape and host pivot.",
"impact": "Elevated privileges for compromised containers. Increased blast radius.",
"recommendation": "Add non-root user to Dockerfiles with educational comments for workshop participants.",
"verification": "self-verified"
},
{
"id": 2,
"severity": "INFO",
"confidence": 10,
"status": "VERIFIED",
"phase": 3,
"phase_name": "Dependency Supply Chain",
"category": "Supply Chain",
"fingerprint": "sha256-spring-boot-eol-2-7-18",
"title": "Spring Boot 2.7.18 is EOL",
"file": "*/pom.xml",
"line": 8,
"description": "Spring Boot 2.7.18 reached end-of-life in November 2023. No further security patches available.",
"exploit_scenario": "Future CVEs in Spring Boot 2.7.x will not be patched. Workshop users deploying to production would be vulnerable.",
"impact": "Unpatched vulnerabilities accumulate over time. Production risk.",
"recommendation": "Add README warning about EOL status and migration path to Spring Boot 3.x for production use.",
"verification": "self-verified"
}
],
"supply_chain_summary": {
"direct_deps": 15,
"transitive_deps": 0,
"critical_cves": 0,
"high_cves": 0,
"install_scripts": 0,
"lockfile_present": false,
"lockfile_tracked": false,
"tools_skipped": ["mvn"]
},
"filter_stats": {
"candidates_scanned": 15,
"hard_exclusion_filtered": 12,
"confidence_gate_filtered": 1,
"verification_filtered": 0,
"reported": 2
},
"totals": {
"critical": 0,
"high": 0,
"medium": 1,
"info": 1,
"tentative": 0
},
"trend": {
"prior_report_date": null,
"resolved": 0,
"persistent": 0,
"new": 2,
"direction": "first_run"
}
}
19 changes: 15 additions & 4 deletions 2_Credential_Repository/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,25 +50,36 @@ Windows 10 example of multiple credentials on a security key. The top choice is


### Dependency configuration
Open the ```pom.xml``` and add the webauthn-server-core and webauthn-server-attestation dependencies. The workshop is known to work with version 1.2.0 of the java-webauthn-server.
Open the ```pom.xml``` and add the webauthn-server-core and webauthn-server-attestation dependencies. The workshop is known to work with version 2.9.0 of the java-webauthn-server.
```xml
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<version>1.2.13</version>
</dependency>
<dependency>
<groupId>com.yubico</groupId>
<artifactId>webauthn-server-core</artifactId>
<!--Check for the latest version at Maven Central-->
<version>1.2.0</version>
<version>2.9.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.yubico</groupId>
<artifactId>webauthn-server-attestation</artifactId>
<!--Check for the latest version at Maven Central-->
<version>1.2.0</version>
<version>2.9.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.3-jre</version>
<scope>compile</scope>
</dependency>
```
Expand Down
37 changes: 32 additions & 5 deletions 2_Credential_Repository/complete/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<version>2.7.18</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
Expand All @@ -16,6 +16,7 @@

<properties>
<java.version>1.8</java.version>
<maven.compiler.release>17</maven.compiler.release>
</properties>

<dependencies>
Expand All @@ -35,6 +36,7 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.46</version>
<optional>true</optional>
</dependency>
<dependency>
Expand All @@ -55,26 +57,51 @@
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<version>1.2.13</version>
</dependency>
<dependency>
<groupId>com.yubico</groupId>
<artifactId>webauthn-server-core</artifactId>
<!--Check for the latest version at Maven Central-->
<version>1.2.0</version>
<version>2.9.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.yubico</groupId>
<artifactId>webauthn-server-attestation</artifactId>
<!--Check for the latest version at Maven Central-->
<version>1.2.0</version>
<version>2.9.0</version>
<scope>compile</scope>
</dependency>
<!-- BouncyCastle for EdDSA support on Java 8 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
<!-- Guava for caching -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.46</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
Expand All @@ -83,7 +110,7 @@
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-webapp-maven-plugin</artifactId>
<!--Check for the latest version at Maven Central-->
<version>1.6.0</version>
<version>2.13.0</version>
<configuration>
<deploymentType>jar</deploymentType>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

package com.example.demo;

import com.yubico.internal.util.CollectionUtil;
import com.yubico.webauthn.data.RelyingPartyIdentity;
import com.yubico.webauthn.extension.appid.AppId;
import com.yubico.webauthn.extension.appid.InvalidAppIdException;
Expand Down Expand Up @@ -53,7 +52,7 @@ public class Config {
private final Optional<AppId> appId;

private Config(Set<String> origins, int port, RelyingPartyIdentity rpIdentity, Optional<AppId> appId) {
this.origins = CollectionUtil.immutableSet(origins);
this.origins = Collections.unmodifiableSet(new HashSet<>(origins));
this.port = port;
this.rpIdentity = rpIdentity;
this.appId = appId;
Expand Down Expand Up @@ -140,15 +139,9 @@ private static RelyingPartyIdentity computeRpIdentity() throws MalformedURLExcep
resultBuilder.id(id);
}

if (icon == null) {
logger.debug("RP icon not given - using none.");
} else {
try {
resultBuilder.icon(Optional.of(new URL(icon)));
} catch (MalformedURLException e) {
logger.error("Invalid icon URL: {}", icon, e);
throw e;
}
// Icon field removed in WebAuthn Level 2 (java-webauthn-server 2.x)
if (icon != null) {
logger.warn("RP icon specified but ignored - icon field removed in WebAuthn Level 2. Value was: {}", icon);
}

final RelyingPartyIdentity result = resultBuilder.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.yubico.internal.util.CollectionUtil;
import com.yubico.webauthn.AssertionResult;
import com.yubico.webauthn.CredentialRepository;
import com.yubico.webauthn.RegisteredCredential;
import com.yubico.webauthn.data.ByteArray;
import com.yubico.webauthn.data.PublicKeyCredentialDescriptor;
import com.example.demo.data.CredentialRegistration;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.NoSuchElementException;
import java.util.Optional;
Expand Down Expand Up @@ -171,7 +171,7 @@ public Optional<RegisteredCredential> lookup(ByteArray credentialId, ByteArray u

@Override
public Set<RegisteredCredential> lookupAll(ByteArray credentialId) {
return CollectionUtil.immutableSet(
return Collections.unmodifiableSet(
storage.asMap().values().stream()
.flatMap(Collection::stream)
.filter(reg -> reg.getCredential().getCredentialId().equals(credentialId))
Expand Down
Loading