From 8d7e505ab4d4a51e5fa66324d5abb73a75dd573f Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 03:27:29 +0000 Subject: [PATCH 1/3] fix: remediate 8 security vulnerabilities C1: Re-enable CSRF protection (remove csrf.disable()), update all HTML forms to use th:action for automatic CSRF token inclusion, convert logout to POST form C2: Add positive amount validation in deposit(), withdraw(), and transferAmount() to prevent negative amount bypass C3: Add @Transactional to deposit(), withdraw(), and transferAmount() to ensure atomicity C4: Add username/password length validation in registerAccount() C6: Replace 'Username already exists' with generic error message to prevent username enumeration C8: Update mysql-connector-java 8.0.33 to mysql-connector-j 9.1.0 (new groupId com.mysql) C10: Add security headers (Content-Type-Options, HSTS) in SecurityConfig Build: Fix maven-compiler-plugin source/target from 1.8 to 17 Also adds H2 test dependency and test application.properties for in-memory database during tests. Co-Authored-By: Angela Lin --- pom.xml | 15 +++++++---- .../bankapp/config/SecurityConfig.java | 5 ++-- .../bankapp/service/AccountService.java | 25 ++++++++++++++++--- src/main/resources/templates/dashboard.html | 12 ++++++--- src/main/resources/templates/login.html | 2 +- src/main/resources/templates/register.html | 4 +-- .../resources/templates/transactions.html | 6 ++++- src/test/resources/application.properties | 6 +++++ 8 files changed, 57 insertions(+), 18 deletions(-) create mode 100644 src/test/resources/application.properties diff --git a/pom.xml b/pom.xml index fc5bfeac..e4c801a0 100644 --- a/pom.xml +++ b/pom.xml @@ -52,9 +52,9 @@ - mysql - mysql-connector-java - 8.0.33 + com.mysql + mysql-connector-j + 9.1.0 runtime @@ -67,6 +67,11 @@ spring-security-test test + + com.h2database + h2 + test + @@ -80,8 +85,8 @@ maven-compiler-plugin 3.8.0 - 1.8 - 1.8 + 17 + 17 diff --git a/src/main/java/com/example/bankapp/config/SecurityConfig.java b/src/main/java/com/example/bankapp/config/SecurityConfig.java index 4dbd1572..0182ede5 100644 --- a/src/main/java/com/example/bankapp/config/SecurityConfig.java +++ b/src/main/java/com/example/bankapp/config/SecurityConfig.java @@ -27,7 +27,6 @@ public static PasswordEncoder passwordEncoder() { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http - .csrf(csrf -> csrf.disable()) .authorizeHttpRequests(authz -> authz .requestMatchers("/register").permitAll() .anyRequest().authenticated() @@ -41,12 +40,14 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti .logout(logout -> logout .invalidateHttpSession(true) .clearAuthentication(true) - .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) + .logoutRequestMatcher(new AntPathRequestMatcher("/logout", "POST")) .logoutSuccessUrl("/login?logout") .permitAll() ) .headers(headers -> headers .frameOptions(frameOptions -> frameOptions.sameOrigin()) + .contentTypeOptions(contentTypeOptions -> {}) + .httpStrictTransportSecurity(hsts -> hsts.includeSubDomains(true).maxAgeInSeconds(31536000)) ); return http.build(); diff --git a/src/main/java/com/example/bankapp/service/AccountService.java b/src/main/java/com/example/bankapp/service/AccountService.java index 5d7d90ec..690fb400 100644 --- a/src/main/java/com/example/bankapp/service/AccountService.java +++ b/src/main/java/com/example/bankapp/service/AccountService.java @@ -12,6 +12,7 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.time.LocalDateTime; @@ -36,19 +37,29 @@ public Account findAccountByUsername(String username) { } public Account registerAccount(String username, String password) { + if (username == null || username.trim().isEmpty() || username.length() < 3) { + throw new RuntimeException("Username must be at least 3 characters"); + } + if (password == null || password.length() < 8) { + throw new RuntimeException("Password must be at least 8 characters"); + } if (accountRepository.findByUsername(username).isPresent()) { - throw new RuntimeException("Username already exists"); + throw new RuntimeException("Registration failed. Please try a different username."); } Account account = new Account(); account.setUsername(username); - account.setPassword(passwordEncoder.encode(password)); // Encrypt password - account.setBalance(BigDecimal.ZERO); // Initial balance set to 0 + account.setPassword(passwordEncoder.encode(password)); + account.setBalance(BigDecimal.ZERO); return accountRepository.save(account); } + @Transactional public void deposit(Account account, BigDecimal amount) { + if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) { + throw new RuntimeException("Amount must be positive"); + } account.setBalance(account.getBalance().add(amount)); accountRepository.save(account); @@ -61,7 +72,11 @@ public void deposit(Account account, BigDecimal amount) { transactionRepository.save(transaction); } + @Transactional public void withdraw(Account account, BigDecimal amount) { + if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) { + throw new RuntimeException("Amount must be positive"); + } if (account.getBalance().compareTo(amount) < 0) { throw new RuntimeException("Insufficient funds"); } @@ -100,7 +115,11 @@ public Collection authorities() { return Arrays.asList(new SimpleGrantedAuthority("USER")); } + @Transactional public void transferAmount(Account fromAccount, String toUsername, BigDecimal amount) { + if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) { + throw new RuntimeException("Amount must be positive"); + } if (fromAccount.getBalance().compareTo(amount) < 0) { throw new RuntimeException("Insufficient funds"); } diff --git a/src/main/resources/templates/dashboard.html b/src/main/resources/templates/dashboard.html index 23a0cc7f..d039ab61 100644 --- a/src/main/resources/templates/dashboard.html +++ b/src/main/resources/templates/dashboard.html @@ -117,7 +117,11 @@ @@ -141,7 +145,7 @@

Account Details

Deposit
-
+
@@ -157,7 +161,7 @@

Account Details

Withdraw
- +
@@ -173,7 +177,7 @@

Account Details

Transfer Money
- +
diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html index 7b40190d..412a68eb 100644 --- a/src/main/resources/templates/login.html +++ b/src/main/resources/templates/login.html @@ -105,7 +105,7 @@

Login

- +
diff --git a/src/main/resources/templates/register.html b/src/main/resources/templates/register.html index e410b74e..b5041caf 100644 --- a/src/main/resources/templates/register.html +++ b/src/main/resources/templates/register.html @@ -105,7 +105,7 @@

Register a New Account

- +
@@ -119,7 +119,7 @@

Register a New Account

Already have an account? Login here

- User already present. +
diff --git a/src/main/resources/templates/transactions.html b/src/main/resources/templates/transactions.html index 307bc5de..e6291b3f 100644 --- a/src/main/resources/templates/transactions.html +++ b/src/main/resources/templates/transactions.html @@ -96,7 +96,11 @@ diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties new file mode 100644 index 00000000..550f3d4d --- /dev/null +++ b/src/test/resources/application.properties @@ -0,0 +1,6 @@ +spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1 +spring.datasource.driver-class-name=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password= +spring.jpa.hibernate.ddl-auto=create-drop +spring.jpa.show-sql=true From 44a1ca30f2e3b425aa1782fa6badf3cbe9b62cc0 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 03:32:22 +0000 Subject: [PATCH 2/3] fix: address review feedback - trim username length check, add deposit error handling - Use username.trim().length() for consistent validation with trim-based emptiness check - Add try-catch in BankController.deposit() to handle amount validation errors gracefully instead of returning a raw 500 error page Co-Authored-By: Angela Lin --- .../example/bankapp/controller/BankController.java | 12 ++++++++++-- .../com/example/bankapp/service/AccountService.java | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/example/bankapp/controller/BankController.java b/src/main/java/com/example/bankapp/controller/BankController.java index 19fcded7..62724436 100644 --- a/src/main/java/com/example/bankapp/controller/BankController.java +++ b/src/main/java/com/example/bankapp/controller/BankController.java @@ -48,10 +48,18 @@ public String login() { } @PostMapping("/deposit") - public String deposit(@RequestParam BigDecimal amount) { + public String deposit(@RequestParam BigDecimal amount, Model model) { String username = SecurityContextHolder.getContext().getAuthentication().getName(); Account account = accountService.findAccountByUsername(username); - accountService.deposit(account, amount); + + try { + accountService.deposit(account, amount); + } catch (RuntimeException e) { + model.addAttribute("error", e.getMessage()); + model.addAttribute("account", account); + return "dashboard"; + } + return "redirect:/dashboard"; } diff --git a/src/main/java/com/example/bankapp/service/AccountService.java b/src/main/java/com/example/bankapp/service/AccountService.java index 690fb400..7a5febc0 100644 --- a/src/main/java/com/example/bankapp/service/AccountService.java +++ b/src/main/java/com/example/bankapp/service/AccountService.java @@ -37,7 +37,7 @@ public Account findAccountByUsername(String username) { } public Account registerAccount(String username, String password) { - if (username == null || username.trim().isEmpty() || username.length() < 3) { + if (username == null || username.trim().isEmpty() || username.trim().length() < 3) { throw new RuntimeException("Username must be at least 3 characters"); } if (password == null || password.length() < 8) { From e328bc494aaad470b48b316343f91774ef949df0 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 03:36:49 +0000 Subject: [PATCH 3/3] fix: trim username before saving to prevent whitespace-padded accounts Co-Authored-By: Angela Lin --- src/main/java/com/example/bankapp/service/AccountService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/example/bankapp/service/AccountService.java b/src/main/java/com/example/bankapp/service/AccountService.java index 7a5febc0..34220e8f 100644 --- a/src/main/java/com/example/bankapp/service/AccountService.java +++ b/src/main/java/com/example/bankapp/service/AccountService.java @@ -40,6 +40,7 @@ public Account registerAccount(String username, String password) { if (username == null || username.trim().isEmpty() || username.trim().length() < 3) { throw new RuntimeException("Username must be at least 3 characters"); } + username = username.trim(); if (password == null || password.length() < 8) { throw new RuntimeException("Password must be at least 8 characters"); }