{"record":{"id":"3c57cc66639fbe05","repo":"instructure/canvas-lms","slug":"insufficient-permission-update-internal-setting","errorCode":null,"errorMessage":"insufficient permission","messagePattern":"insufficient permission","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/update_internal_setting.rb","lineNumber":28,"sourceCode":"#\n# 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\nclass Mutations::UpdateInternalSetting < Mutations::BaseMutation\n  graphql_name \"UpdateInternalSetting\"\n\n  argument :internal_setting_id, ID, required: true, prepare: GraphQLHelpers.relay_or_legacy_id_prepare_func(\"InternalSetting\")\n  argument :value, String, required: true\n\n  field :internal_setting, Types::InternalSettingType, null: false\n  def resolve(input:)\n    if !Account.site_admin.grants_right?(current_user, :manage_internal_settings) || (internal_setting = Setting.find(input[:internal_setting_id])).secret\n      raise GraphQL::ExecutionError, \"insufficient permission\"\n    end\n\n    unless input[:value].nil?\n      Setting.set(internal_setting.name, input[:value])\n      internal_setting.reload\n    end\n\n    {\n      internal_setting:\n    }\n  rescue ActiveRecord::RecordNotFound\n    raise GraphQL::ExecutionError, \"not found\"\n  end\nend\n","sourceCodeStart":10,"sourceCodeEnd":43,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/update_internal_setting.rb#L10-L43","documentation":"updateInternalSetting raises this GraphQL::ExecutionError when the caller lacks :manage_internal_settings on Account.site_admin OR the targeted Setting is marked secret. Internal settings are site-admin-only; even site admins may not read/modify settings flagged secret through this mutation.","triggerScenarios":"Calling updateInternalSetting as a non-site-admin user; or as a site admin when Setting.find(input[:internal_setting_id]).secret returns true — the combined condition in the single if-statement raises for either case, so a secret setting yields 'insufficient permission' even for authorized admins.","commonSituations":"Using a regular account-admin token for a site-level setting, attempting to edit a secret setting (e.g. encrypted credentials-backed) that Canvas deliberately shields, or a typo'd/ambiguous ID resolving to the wrong Setting record.","solutions":["Confirm the user has :manage_internal_settings on Account.site_admin (root Site Admin account), granting via site admin role if needed.","If the setting is secret, modify it out-of-band (Rails console with Setting.set, or the config mechanism that owns it) — the GraphQL mutation will always refuse.","Double-check the internal_setting_id resolves to the intended Setting and is not unexpectedly marked secret."],"exampleFix":"// Rails console\n# before: denied via mutation for a secret setting\n# after: set directly\nAccount.site_admin.grants_right?(user, :manage_internal_settings) # => true\nSetting.set(setting_name, \"new_value\")","handlingStrategy":"validation","validationCode":"// Rails console pre-check\nraise 'not a site admin' unless Account.site_admin.grants_right?(current_user, :manage_internal_settings)","typeGuard":"function isSiteAdminWithInternalSettings(viewer) { return viewer?.permissions?.includes('manage_internal_settings') ?? false }","tryCatchPattern":"try {\n  await updateInternalSetting({ variables: { input } })\n} catch (e) {\n  if (e.graphQLErrors?.some(g => g.message === 'insufficient permission')) {\n    // fall back to Rails console / config pipeline for secret settings\n  } else throw e\n}","preventionTips":["Restrict internal-setting mutations to site-admin service credentials","Never expose secret settings through the GraphQL path; manage them in console/config","Verify target Setting IDs before mutating","Keep an inventory of which settings are marked secret"],"tags":["graphql","authorization","permissions","site-admin"],"backgroundTag":"insufficient-permissions","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"}