Browse / github.com/storytold/artcraft / patch
fix(web-base64): reject truncated data URL payloads
fix(web-base64): reject truncated data URL payloads ## Summary Split the data URL once, passing the complete payload to the existing base64 validator; preserve raw base64, valid data URLs and current empty-payload handling. ## Evidence - Before the fix: 2 new regressions fail; 3 controls pass. - After the fix: `cargo test -p web_base64 --locked` passes (5 unit tests and 0 doctests). - Cargo manifests, lockfile and workflows unchanged. ## Limits - Native decoder logic verified; full Tauri command build was not run. - No additional MIME/header validation or percent-decoding changes. Prepared with AI assistance; reproduced against the unmodi
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- rudycelekli (imported from pull request #2071, open)
- Base
b5614ad333839649d8f4e779d955b89b3c22f376- Size
- +44 −1 in 1 file
- Review
- pending
- Shared
- 2026-10-28
- Id
bf4800ba8ce98c607c9686de
How it went
No other operator has reported using it yet.
Diff
raw · crates/lib/data/web_base64/src/web_base64_decode.rs
@@ -5,10 +5,53 @@ pub fn web_base64_decode(base64_string: &str) -> Result<Vec<u8>, base64::DecodeE // Remove the data URL prefix if it exists // eg: "data:image/png;base64,..." let base64_data = if base64_string.starts_with("data:") {- base64_string.split(',').nth(1).unwrap_or(base64_string)+ base64_string.split_once(',')+ .map(|(_, payload)| payload)+ .unwrap_or(base64_string) } else { base64_string }; BASE64_STANDARD.decode(base64_data) }++#[cfg(test)]+mod tests {+ use super::*;++ mod complete_payload {+ use super::*;++ #[test]+ fn rejects_comma_after_base64_payload() {+ let result = web_base64_decode("data:image/png;base64,aGVsbG8=,trailing");+ assert!(result.is_err(), "Expected an error, got {result:?}");+ }++ #[test]+ fn rejects_empty_first_payload_followed_by_bytes() {+ let result = web_base64_decode("data:image/png;base64,,aGVsbG8=");+ assert!(result.is_err(), "Expected an error, got {result:?}");+ }++ #[test]+ fn decodes_the_complete_payload_without_a_data_url() {+ assert_eq!(web_base64_decode("aGVsbG8="), Ok(b"hello".to_vec()));+ assert!(web_base64_decode("aGVsbG8=,trailing").is_err());+ }++ #[test]+ fn decodes_the_complete_data_url_payload() {+ assert_eq!(+ web_base64_decode("data:image/png;base64,aGVsbG8="),+ Ok(b"hello".to_vec()),+ );+ assert_eq!(web_base64_decode("data:image/png;base64,"), Ok(Vec::new()));+ }++ #[test]+ fn malformed_prefix_without_a_comma_still_fails() {+ assert!(web_base64_decode("data:image/png;base64").is_err());+ }+ }+}