{"record":{"id":"80e74ceab2e3708d","repo":"carrierwaveuploader/carrierwave","slug":"invalid-cache-id","errorCode":null,"errorMessage":"invalid cache id","messagePattern":"invalid cache id","errorType":"exception","errorClass":"CarrierWave::InvalidParameter","httpStatus":null,"severity":"error","filePath":"lib/carrierwave/uploader/cache.rb","lineNumber":204,"sourceCode":"        File.join(*[cache_dir, @cache_id, for_file].compact)\n      end\n\n    protected\n\n      attr_reader :cache_id\n\n    private\n\n      def workfile_path(for_file=original_filename)\n        File.join(CarrierWave.tmp_path, @cache_id, version_name.to_s, for_file)\n      end\n\n      attr_reader :original_filename\n\n      def cache_id=(cache_id)\n        # Earlier version used 3 part cache_id. Thus we should allow for\n        # the cache_id to have both 3 part and 4 part formats.\n        raise CarrierWave::InvalidParameter, \"invalid cache id\" unless cache_id =~ /\\A(-)?[\\d]+\\-[\\d]+(\\-[\\d]{4})?\\-[\\d]{4}\\z/\n        @cache_id = cache_id\n      end\n\n      def original_filename=(filename)\n        raise CarrierWave::InvalidParameter, \"invalid filename\" if filename =~ CarrierWave::SanitizedFile.sanitize_regexp\n        @original_filename = filename\n      end\n\n      def cache_storage\n        @cache_storage ||= (self.class.cache_storage || self.class.storage).new(self)\n      end\n\n      # We can override the full_original_filename method in other modules\n      def full_original_filename\n        forcing_extension(original_filename)\n      end\n    end # Cache\n  end # Uploader","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/carrierwaveuploader/carrierwave/blob/b5f0abe10ecf6500309fc83e0e8969cf57ba690e/lib/carrierwave/uploader/cache.rb#L186-L222","documentation":"Raised as CarrierWave::InvalidParameter by Uploader::Cache#cache_id= when the cache id portion of a cache name does not match /\\A(-)?\\d+-\\d+(-\\d{4})?-\\d{4}\\z/. CarrierWave cache names look like 'TIMEINT-PID-COUNTER-RND/filename.ext' (the regex also tolerates the older 3-part format); anything else is rejected before the cache storage is touched, as an anti-tampering measure on the hidden cache form field.","triggerScenarios":"uploader.retrieve_from_cache!(params[:image_cache]) where the submitted value was truncated, edited, or is a different field entirely: passing the filename alone, passing the full 'cache_id/filename' with a malformed id segment (letters where digits belong, missing parts), or an attacker probing the cache param.","commonSituations":"Re-rendering a form after validation errors where the hidden field name no longer matches params (e.g. nested attributes, form renaming); copy-pasting cache values between environments; manual curl posts omitting the id pieces; cache ids generated by a newer/older CarrierWave than the one re-reading them.","solutions":["Validate the cache param against the expected pattern before calling retrieve_from_cache!","Check the form: the hidden field must carry the exact uploader.cache_name value (use the provided form helpers so the round-trip is automatic)","Rescue CarrierWave::InvalidParameter and treat it as a fresh upload instead of crashing","Regenerate the cache value by re-uploading if the id came from a different CarrierWave version"],"exampleFix":"# before\nuploader.retrieve_from_cache!(params[:image_cache]) # tampered value -> InvalidParameter\n\n# after\nCACHE_ID = /\\A-?\\d+-\\d+(-\\d{4})?-\\d{4}\\z/.freeze\ncache_name = params[:image_cache].to_s\nif cache_name.split('/', 2).first =~ CACHE_ID\n  uploader.retrieve_from_cache!(cache_name)\nelse\n  uploader.cache!(params[:image]) # fall back to the fresh upload\nend","handlingStrategy":"validation","validationCode":"CACHE_NAME = /\\A(-?\\d+-\\d+(-\\d{4})?-\\d{4})\\/[^\\/]+\\z/.freeze\n\ndef valid_cache_name?(name)\n  name.to_s.match?(CACHE_NAME)\nend\n\nuploader.retrieve_from_cache!(cache_name) if valid_cache_name?(params[:image_cache])","typeGuard":"def cache_param?(value)\n  value.is_a?(String) && value.match?(CACHE_NAME)\nend","tryCatchPattern":"begin\n  uploader.retrieve_from_cache!(params[:image_cache])\nrescue CarrierWave::InvalidParameter\n  uploader.cache!(params[:image]) # treat as a fresh upload\nend","preventionTips":["Always render the hidden cache field with the uploader-provided cache_name value (keep_the_cache / form helpers), never rebuild it in JS","Regex-check the cache param (id segment: optional -, digits, digits, optional 4-digit, 4-digit) before retrieve_from_cache!","Rescue CarrierWave::InvalidParameter and degrade gracefully to a fresh upload instead of a 500"],"tags":["carrierwave","cache","parameter-validation","form-round-trip","security"],"backgroundTag":"invalid-cache-id","analyzedSha":"b5f0abe10ecf6500309fc83e0e8969cf57ba690e","analyzedAt":"2026-08-21T18:07:27.715Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}