{"record":{"id":"6b310529ed564b5d","repo":"instructure/canvas-lms","slug":"invalid-value-for-k","errorCode":null,"errorMessage":"invalid value for #{k}","messagePattern":"invalid value for #(.+?)","errorType":"exception","errorClass":"HmacHelper::Error","httpStatus":null,"severity":"error","filePath":"app/helpers/hmac_helper.rb","lineNumber":30,"sourceCode":"# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY\n# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR\n# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more\n# details.\n#\n# You should have received a copy of the GNU Affero General Public License along\n# with this program. If not, see <http://www.gnu.org/licenses/>.\n\nmodule HmacHelper\n  # returns parsed json after verification\n  def extract_blob(hmac, json, expected_values = {})\n    unless Canvas::Security.verify_hmac_sha1(hmac, json)\n      raise Error, \"signature doesn't match.\"\n    end\n\n    blob = JSON.parse(json)\n\n    expected_values.each do |k, v|\n      raise Error, \"invalid value for #{k}\" if blob[k] != v\n    end\n\n    blob\n  end\n\n  class Error < StandardError; end\nend\n","sourceCodeStart":12,"sourceCodeEnd":38,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/helpers/hmac_helper.rb#L12-L38","documentation":"After HMAC verification succeeds, extract_blob checks optional expected_values against the parsed blob and raises Error \"invalid value for #{k}\" when blob[k] != v. It is a post-verification semantic check that signed content matches what the caller expects.","triggerScenarios":"Calling extract_blob(hmac, json, {course_id: 42}) where the signed blob contains a different or missing course_id — e.g. reusing a signed URL for another course, or comparing string '42' vs integer 42.","commonSituations":"Bookmarked/forwarded signed links used in a different account/course context; type mismatches after JSON round-trips; secret rotation making the blob valid but stale.","solutions":["Compare with the correct expected value/type for the key (strings vs integers after JSON.parse).","Regenerate the signed payload with the expected values baked in.","Remove the key from expected_values if it is not guaranteed stable.","Inspect the blob (JSON.parse the json param) to see the actual value and align expectations."],"exampleFix":"// before\nextract_blob(hmac, json, { user_id: \"17\" })\n// after\nextract_blob(hmac, json, { user_id: 17 }) # match JSON-parsed type","handlingStrategy":"try-catch","validationCode":"blob = JSON.parse(json)\nreturn nil unless expected_values.all? { |k, v| blob[k] == v }","typeGuard":null,"tryCatchPattern":"begin\n  blob = extract_blob(hmac, json, expected)\nrescue HmacHelper::Error => e\n  Rails.logger.warn(\"blob expected-values mismatch: #{e.message}\")\n  return nil\nend","preventionTips":["Match expected value types to what JSON.parse returns","Only assert expected_values on keys guaranteed stable in the signed payload","Regenerate signatures when the embedded values change"],"tags":["hmac","validation","payload-mismatch"],"backgroundTag":"invalid-argument-value","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}