Using "heredoc" Breaks Commands #178

Closed
opened 2026-01-19 18:29:31 +00:00 by michael · 2 comments
Owner

Originally created by @hackerman-jpeg on GitHub.

Summary

Any (or most) commands in the CIS and STIG that uses the heredoc will probably break the command. For example the AirDrop Disable CIS Check:

/usr/bin/osascript -l JavaScript << EOS
  $.NSUserDefaults.alloc.initWithSuiteName('com.apple.applicationaccess')\
  .objectForKey('allowAirDrop').js
  EOS 

If executed as is, returns new line and no result, due to how this command is structured.
For MacOS 13, it is much more robust and concise to use:

defaults read com.apple.applicationaccess allowAirDrop

Or if we must stick to the same syntax, I would structure:

/usr/bin/osascript -l JavaScript -e "ObjC.import('Foundation'); $.NSUserDefaults.alloc.initWithSuiteName('com.apple.applicationaccess').objectForKey('allowAirDrop')"

Also, if the key has never been set, it will return the following error:

The domain/default pair of (com.apple.applicationaccess, allowAirDrop) does not exist

Therefore the boolean must be set first to even return status 0.

Steps to reproduce

Run the command in MacOS 13 terminal as is written in Benchmark:

/usr/bin/osascript -l JavaScript << EOS
  $.NSUserDefaults.alloc.initWithSuiteName('com.apple.applicationaccess')\
  .objectForKey('allowAirDrop').js
  EOS

Operating System version

macOS: 22E261 Kernel: 22.4.0

Intel or Apple Silicon

Apple Silicon

What is the current bug behavior?

Returns new line for infinite user input.

And also:

The domain/default pair of (com.apple.applicationaccess, allowAirDrop) does not exist

What is the expected correct behavior?

Runs the OS command in the script.

Relevant logs and/or screenshots

image

Output of checks

See above.

Possible fixes

It is important to note that if the boolean is not set, it will return the error `The domain/default pair of (com.apple.applicationaccess, allowAirDrop) does not exist'. Therefore the boolean must be set to disable AirDrop first:

/usr/bin/defaults write com.apple.applicationaccess allowAirDrop -bool false

Fix 1

Refactor to the below:

/usr/bin/osascript -l JavaScript -e "ObjC.import('Foundation'); $.NSUserDefaults.alloc.initWithSuiteName('com.apple.applicationaccess').objectForKey('allowAirDrop')"

Fix 2

Use a better command for MacOS13:

defaults read com.apple.applicationaccess allowAirDrop

Or put this same command into a script as was done before (for easier auditing):

if [ "$(defaults read com.apple.applicationaccess allowAirDrop)" -eq 0 ]; then
  echo "AirDrop is disabled."
else
  echo "AirDrop is enabled."
fi
Originally created by @hackerman-jpeg on GitHub. ### Summary Any (or most) commands in the CIS and STIG that uses the [heredoc](https://tldp.org/LDP/abs/html/here-docs.html) will probably break the command. For example the [AirDrop Disable CIS Check](https://github.com/usnistgov/macos_security/blob/10705d95975fedf195d73ca1f0200ecc1b5c6158/rules/os/os_airdrop_disable.yaml): ```bash /usr/bin/osascript -l JavaScript << EOS $.NSUserDefaults.alloc.initWithSuiteName('com.apple.applicationaccess')\ .objectForKey('allowAirDrop').js EOS ``` If executed as is, returns new line and no result, due to how this command is structured. For MacOS 13, it is much more robust and concise to use: ```bash defaults read com.apple.applicationaccess allowAirDrop ``` Or if we must stick to the same syntax, I would structure: ```bash /usr/bin/osascript -l JavaScript -e "ObjC.import('Foundation'); $.NSUserDefaults.alloc.initWithSuiteName('com.apple.applicationaccess').objectForKey('allowAirDrop')" ``` Also, if the key has never been set, it will return the following error: ```bash The domain/default pair of (com.apple.applicationaccess, allowAirDrop) does not exist ``` Therefore the boolean must be set first to even return status `0`. ### Steps to reproduce Run the command in MacOS 13 terminal as is written in Benchmark: ```bash /usr/bin/osascript -l JavaScript << EOS $.NSUserDefaults.alloc.initWithSuiteName('com.apple.applicationaccess')\ .objectForKey('allowAirDrop').js EOS ``` ### Operating System version `macOS: 22E261 Kernel: 22.4.0` ### Intel or Apple Silicon Apple Silicon ### What is the current *bug* behavior? Returns new line for infinite user input. And also: ```bash The domain/default pair of (com.apple.applicationaccess, allowAirDrop) does not exist ``` ### What is the expected *correct* behavior? Runs the OS command in the script. ### Relevant logs and/or screenshots <img width="529" alt="image" src="https://user-images.githubusercontent.com/41294610/233903818-08769425-e372-4679-bb7d-883432190b4a.png"> ### Output of checks See above. ### Possible fixes It is important to note that if the boolean is not set, it will return the error `The domain/default pair of (com.apple.applicationaccess, allowAirDrop) does not exist'. Therefore the boolean must be set to disable AirDrop first: ```bash /usr/bin/defaults write com.apple.applicationaccess allowAirDrop -bool false ``` #### Fix 1 Refactor to the below: ```bash /usr/bin/osascript -l JavaScript -e "ObjC.import('Foundation'); $.NSUserDefaults.alloc.initWithSuiteName('com.apple.applicationaccess').objectForKey('allowAirDrop')" ``` #### Fix 2 Use a better command for MacOS13: ```bash defaults read com.apple.applicationaccess allowAirDrop ``` Or put this same command into a script as was done before (for easier auditing): ```bash if [ "$(defaults read com.apple.applicationaccess allowAirDrop)" -eq 0 ]; then echo "AirDrop is disabled." else echo "AirDrop is enabled." fi ```
Author
Owner

@hackerman-jpeg commented on GitHub:

To summarise:

1. Use defaults read when possible

2. Use a more clean syntax for script format, and remove EOF/ heredoc, as it muddy and causes errors.

@hackerman-jpeg commented on GitHub: To summarise: ## 1. Use `defaults read` when possible ## 2. Use a more clean syntax for script format, and remove EOF/ `heredoc`, as it muddy and causes errors.
Author
Owner

@robertgendler commented on GitHub:

Defaults to read the domain in memory is not ideal as it requires a user to be logged in. It will not read from the preferences daemon unless a user session at loginwindow is established.

The spacing and heredoc was done to make it easier to read. When you remove it and put the command like in your osascript example the PDF wraps kind of nicely, but the HTML document makes the horizontal scrolling which we thought wasn't ideal.

The heredoc also makes it a lot easier when there's complex checks with multiple keys.

@robertgendler commented on GitHub: Defaults to read the domain in memory is not ideal as it requires a user to be logged in. It will not read from the preferences daemon unless a user session at loginwindow is established. The spacing and heredoc was done to make it easier to read. When you remove it and put the command like in your osascript example the PDF wraps kind of nicely, but the HTML document makes the horizontal scrolling which we thought wasn't ideal. The heredoc also makes it a lot easier when there's complex checks with multiple keys.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: usnistgov/macos_security#178