{"record":{"id":"b3f3a7dc2d63367e","repo":"puppetlabs/puppet","slug":"invalid-dacl","errorCode":null,"errorMessage":"Invalid DACL","messagePattern":"Invalid DACL","errorType":"exception","errorClass":"Puppet::Util::Windows::Error","httpStatus":null,"severity":"error","filePath":"lib/puppet/util/windows/security.rb","lineNumber":468,"sourceCode":"\n    Puppet::Util::Windows::SID.string_to_sid_ptr(sid) do |sid_ptr|\n      if Puppet::Util::Windows::SID.IsValidSid(sid_ptr) == FFI::WIN32_FALSE\n        raise Puppet::Util::Windows::Error, _(\"Invalid SID\")\n      end\n\n      if AddAccessDeniedAceEx(acl, ACL_REVISION, inherit, mask, sid_ptr) == FFI::WIN32_FALSE\n        raise Puppet::Util::Windows::Error, _(\"Failed to add access control entry\")\n      end\n    end\n\n    # ensure this method is void if it doesn't raise\n    nil\n  end\n\n  def parse_dacl(dacl_ptr)\n    # REMIND: need to handle NULL DACL\n    if IsValidAcl(dacl_ptr) == FFI::WIN32_FALSE\n      raise Puppet::Util::Windows::Error, _(\"Invalid DACL\")\n    end\n\n    dacl_struct = ACL.new(dacl_ptr)\n    ace_count = dacl_struct[:AceCount]\n\n    dacl = Puppet::Util::Windows::AccessControlList.new\n\n    # deny all\n    return dacl if ace_count == 0\n\n    0.upto(ace_count - 1) do |i|\n      FFI::MemoryPointer.new(:pointer, 1) do |ace_ptr|\n        next if GetAce(dacl_ptr, i, ace_ptr) == FFI::WIN32_FALSE\n\n        # ACE structures vary depending on the type. We are only concerned with\n        # ACCESS_ALLOWED_ACE and ACCESS_DENIED_ACEs, which have the same layout\n        ace = GENERIC_ACCESS_ACE.new(ace_ptr.get_pointer(0)) # deref LPVOID *\n","sourceCodeStart":450,"sourceCodeEnd":486,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/util/windows/security.rb#L450-L486","documentation":"Raised by parse_dacl when the DACL pointer returned by GetSecurityInfo for a filesystem object fails the Win32 IsValidAcl validation. That means the discretionary ACL read off the object is structurally invalid or the pointer is null (the code has a REMIND comment that a NULL DACL is not handled). It surfaces through get_security_descriptor when Puppet reads permissions for the group/owner/allow/deny properties.","triggerScenarios":"get_security_descriptor (or Puppet's acl provider reading mode) on a file whose security descriptor is corrupted, on an object whose DACL is NULL (no DACL present, so IsValidAcl receives a null pointer), or on reparse points/special filesystem objects where the returned DACL structure is malformed.","commonSituations":"Corrupted NTFS metadata after disk issues; files created by non-Windows systems or unusual drivers; objects with a NULL DACL (everyone-full-access) that Puppet tries to manage; some clustered or ReFS layouts.","solutions":["Check whether the object really has a DACL before parsing (a NULL DACL is legal and means 'grant everyone')","Rebuild the object's security: copy data elsewhere, delete and recreate the file, or reset with icacls <path> /reset","Exclude the affected path from Puppet management until its descriptor is repaired","Inspect e.code from the error for the underlying Win32 failure reason"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"begin\n  sd = Puppet::Util::Windows::Security.get_security_descriptor(path)\nrescue Puppet::Util::Windows::Error => e\n  raise unless e.message.include?('Invalid DACL')\n  raise Puppet::Error, \"Security descriptor on #{path} is unreadable (NULL or corrupt DACL); run icacls '#{path}' /reset\"\nend","preventionTips":["Audit target trees with icacls before managing them to catch corrupt descriptors early","Do not assume every object has a DACL; treat NULL DACL as 'everyone full control'","Keep backups that include ACLs so a /reset loses nothing"],"tags":["windows","acl","security","dacl","corruption","win32"],"backgroundTag":"corrupt-security-descriptor","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}