INSTALLING QRGUARD IN YOUR ODC APP------------------------------------1. Download QRGuard v0.4.0 ExternalLibrary.zip from the OutSystems Forge.2. Open ODC Portal, go to Extensibility -> External Logic -> Upload.3. Select ExternalLibrary.zip. Wait for the upload to finish.4. Open the ODC Studio app or module that will consume QRGuard.5. Manage Dependencies -> QRGuard. Tick the four Server Actions and the three Structures (QRScanBatchResult, QRScanResult, RedactQRCodesResult).6. Publish the module. No server-side configuration, Site Property, or role assignment is required. Every call is stateless.USING THE SERVER ACTIONS------------------------Four Server Actions cover the four common scenarios. All are stateless,side-effect-free, and safe on any input (non-image inputs returnIsPassthrough=true with no exception).ContainsQRCodeFast Boolean shortcut - true when at least one QR is decodable on anyframe. Use for blanket rejection where QR codes are never a legitimateinput (support chatbots, document summarisers, product-imageclassifiers). Inputs Image Binary Data Output BooleanScanImageFull multi-frame + multi-QR scan with per-payload classification. Usewhen QR codes may be legitimate (product catalogues, receiptprocessors) and you need per-content filtering rather than blanketrejection. Inputs Image Binary Data CustomInjectionPatterns Text optional; pipe-separated extra patterns unioned with the 18 built-in list; empty entries skipped, trimmed, lowercased, deduplicated MaxImageDimension Integer 0 = default 4096; positive clamped to floor 512 SuspiciousLengthThreshold Integer 0 = default 500; positive clamped to floor 20 Output QRScanBatchResult ContainsAnyQRCode Boolean QRCodeCount Integer = QRCodes.Length AnyIsSuspicious Boolean QRCodes List of QRScanResult IsPassthrough Boolean true only when input is not an image ProcessingError Text Nested QRScanResult DecodedContent Text IsSuspicious Boolean DetectedPatterns Text pipe-separated matched patterns FrameIndex Integer 0-based; >0 only for multi-frame formatsDecodeAllQRCodesSame shape as ScanImage but pattern filtering is skipped by contract.Every returned QRScanResult has IsSuspicious=false andDetectedPatterns="". Use when the caller wants raw payloads for itsown downstream processing. Inputs Image Binary Data MaxImageDimension Integer same semantics as ScanImage Output QRScanBatchResult (see above)RedactQRCodesLocates every QR's bounding box and overwrites each matching QR with asolid fill colour. Output re-encoded in the same format as the input(Jpeg to Jpeg, Png to Png, etc.). Use when QR codes are expected inthe input (receipts, product photos) but suspicious payloads must beneutralised in place rather than rejecting the whole upload. Inputs Image Binary Data CustomInjectionPatterns Text applies only in "Suspicious" mode; same semantics as ScanImage MaxImageDimension Integer same semantics as ScanImage RedactMode Text "Suspicious" (default; empty also = "Suspicious") redacts only flagged QRs; "All" redacts every QR regardless of content and ignores the length threshold FillColor Text hex; "#RRGGBB" recommended; "#AARRGGBB" accepted; empty or invalid = solid black SuspiciousLengthThreshold Integer applies only in "Suspicious" mode Output RedactQRCodesResult CleanImage Binary Data sanitised image; original bytes when IsPassthrough or error OriginalFormat Text empty when IsPassthrough=true TotalQRCodeCount Integer RedactedCount Integer = TotalQRCodeCount in "All" mode IsPassthrough Boolean ProcessingError TextRecommended pipeline 1. Receive the uploaded image as a Binary Data input. 2. Call FileMetadataStrip.StripFileMetadata to remove EXIF/IPTC/XMP. 3. Call StegoGuard.RecompressImage on the CleanFile from step 2. 4. Call the QRGuard action for your feature (pass optional parameters as "", 0, "", 0 to use defaults; RedactQRCodes uses "Suspicious" and "#000000" for the two Text defaults): - ContainsQRCode -> reject if it returns true - ScanImage -> reject if AnyIsSuspicious is true; if ContainsAnyQRCode is true, validate each QRCodes[i].DecodedContent against the expected format (product SKU, receipt number, allow-listed URL) - DecodeAllQRCodes -> inspect QRCodes[i].DecodedContent yourself - RedactQRCodes -> forward CleanImage; suspicious QRs are overwritten in place, legitimate QRs remain intact in "Suspicious" mode 5. Forward the sanitised image to the vision AI API.CONFIGURATION AND TUNING------------------------QRGuard has no Site Properties and no configuration screen. Behaviouris controlled entirely through the input parameters of each ServerAction.Injection patterns18 case-insensitive substring matches are built in: ignore previous,ignore all previous, disregard previous, disregard all previous,forget previous, forget all previous, system prompt, new instructions,you are now, you must now, act as if, pretend you are, pretend to be,your new role, developer mode, jailbreak, dan mode, do anything now.Pass extra case-insensitive patterns via CustomInjectionPatterns as apipe-separated Text (e.g. "reveal the api key|forget the safetyrules"). Empty entries skipped; each entry trimmed and lowercased;duplicates deduplicated. Empty string = built-in list only.DecodeAllQRCodes deliberately ignores this parameter.Suspicious-length thresholdDecoded content longer than SuspiciousLengthThreshold is flagged assuspicious regardless of pattern match. Long natural-language QRs arethe most common prompt-injection carrier. 0 = default 500 chars Positive value = custom threshold, clamped to floor of 20 Very high value = effectively disables the length checkApplied by ScanImage and by RedactQRCodes in "Suspicious" mode.Downscaling capLarge images are downscaled per-frame before ZXing scans. Aspectratio preserved. 0 = default 4096 pixels (wider or taller) Positive value = custom cap, clamped to floor of 512 On RedactQRCodes = bounding boxes are mapped back to the original resolution before painting, so output dimensions are preservedRedaction fill colour "#RRGGBB" recommended, e.g. "#000000" black, "#FFFFFF" white "#AARRGGBB" with alpha channel "" solid black invalid solid black (redaction is never silently skipped)Passthrough contractQRScanBatchResult.IsPassthrough and RedactQRCodesResult.IsPassthroughare true when the input is not a recognised image (plain text, PDF,arbitrary bytes, empty buffer). False when the input is an image,regardless of whether any QR was found and regardless of whetherProcessingError is non-empty. Use this to distinguish "not an image"from "we looked and found nothing".Error handlingAll four actions swallow decode-level exceptions and populateProcessingError with a human-readable message. Log ProcessingError fordiagnostics; when non-empty, treat the input as unknown and fail-closed in security-sensitive flows.Security pipeline positionLayer 1, Priority 4. Run after FileMetadataStrip (Priority 1) andStegoGuard (Priorities 2, 3), before sending to any vision-capable AIAPI. QR codes survive JPEG recompression and Gaussian filtering thanksto Reed-Solomon error correction, so QRGuard is a necessary complementto StegoGuard - one cannot substitute for the other.SUPPORTED FILE FORMATS----------------------Every format is covered by a per-format xUnit regression test (479ODC tests, part of a 1,322-test matrix).Full QR round-trip via Magick.NET-Q8 (30 formats): JPEG, PNG (Png8/24/32/48/64/00 subformats regression-locked), GIF, BMP, TIFF, WebP,AVIF, JXL, JP2, J2C, PSD, PSB, DDS, EXR, HDR, QOI, DPX, CIN, SGI, SUN,PCX, PBM, PGM, PPM, PNM, FITS, XBM, XPM, MSVG, DIB, DCX.Multi-frame containers (QR detected on any frame, FrameIndexreported): animated GIF/WebP, multi-frame TIFF, APNG, MNG, DCX.Recognised without full decode (EmptyBatchResult): TGA, WBMP, ICO.Synthetic-byte passthrough: HEIC/HEIF/AVIF (ftyp brands), MPO, SVG,UHDR, camera-RAW (DNG/CR2/NEF/ARW/PEF/ORF/RAF/X3F), JXR, JBIG, XCF,WMF, AI, PCD, PICT, DICOM.Non-image inputs (plain text, PDF, DOCX, empty) returnQRScanBatchResult with IsPassthrough=true, ContainsAnyQRCode=false,empty QRCodes, empty ProcessingError.