diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4d662cf3..cb328f11 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@
     * Setting the following pyscript variables:
         * `__name__`: __main__
         * `__file__`: script path (as typed, ~ will be expanded)
+    * Only tab complete after redirection tokens if redirection is allowed
 * Other
     * Removed undocumented `py run` command since it was replaced by `run_pyscript` a while ago
 
diff --git a/cmd2/cmd2.py b/cmd2/cmd2.py
index 3b1fbb6f..5a728e56 100644
--- a/cmd2/cmd2.py
+++ b/cmd2/cmd2.py
@@ -1050,8 +1050,8 @@ class Cmd(cmd.Cmd):
                         in_pipe = False
                         in_file_redir = True
 
-                # Not a redirection token
-                else:
+                # Only tab complete after redirection tokens if redirection is allowed
+                elif self.allow_redirection:
                     do_shell_completion = False
                     do_path_completion = False
 

Tab completions after pipe | is still active on disabled redirection
With
self.allow_redirection = False

I can list system commands using any_command | <TAB>

My goal is to lock user in CLI without any way to run system command or access system files and with that in mind default cmd2 is quite "open"
diff --git a/tests/test_completion.py b/tests/test_completion.py
index f545c8f9..e13d87de 100755
--- a/tests/test_completion.py
+++ b/tests/test_completion.py
@@ -902,11 +902,6 @@ class RedirCompType(enum.Enum):
     DEFAULT = 3,
     NONE = 4
 
-    """   
-    fake > > 
-    fake | grep > file 
-    fake | grep > file > 
-    """
 
 @pytest.mark.parametrize('line, comp_type', [
     ('fake', RedirCompType.DEFAULT),
@@ -933,31 +928,40 @@ class RedirCompType(enum.Enum):
     ('fake > file >>', RedirCompType.NONE),
 ])
 def test_redirect_complete(cmd2_app, monkeypatch, line, comp_type):
-    shell_cmd_complete_mock = mock.MagicMock(name='shell_cmd_complete')
-    monkeypatch.setattr("cmd2.Cmd.shell_cmd_complete", shell_cmd_complete_mock)
-
-    path_complete_mock = mock.MagicMock(name='path_complete')
-    monkeypatch.setattr("cmd2.Cmd.path_complete", path_complete_mock)
-
-    default_complete_mock = mock.MagicMock(name='fake_completer')
-
-    text = ''
-    line = '{} {}'.format(line, text)
-    endidx = len(line)
-    begidx = endidx - len(text)
+    # Test both cases of allow_redirection
+    cmd2_app.allow_redirection = True
+    for count in range(2):
+        shell_cmd_complete_mock = mock.MagicMock(name='shell_cmd_complete')
+        monkeypatch.setattr("cmd2.Cmd.shell_cmd_complete", shell_cmd_complete_mock)
+
+        path_complete_mock = mock.MagicMock(name='path_complete')
+        monkeypatch.setattr("cmd2.Cmd.path_complete", path_complete_mock)
+
+        default_complete_mock = mock.MagicMock(name='fake_completer')
+
+        text = ''
+        line = '{} {}'.format(line, text)
+        endidx = len(line)
+        begidx = endidx - len(text)
+
+        cmd2_app._redirect_complete(text, line, begidx, endidx, default_complete_mock)
+
+        if comp_type == RedirCompType.SHELL_CMD:
+            shell_cmd_complete_mock.assert_called_once()
+        elif comp_type == RedirCompType.PATH:
+            path_complete_mock.assert_called_once()
+        elif comp_type == RedirCompType.DEFAULT:
+            default_complete_mock.assert_called_once()
+        else:
+            shell_cmd_complete_mock.assert_not_called()
+            path_complete_mock.assert_not_called()
+            default_complete_mock.assert_not_called()
 
-    cmd2_app._redirect_complete(text, line, begidx, endidx, default_complete_mock)
+        # Do the next test with allow_redirection as False
+        cmd2_app.allow_redirection = False
+        if comp_type != RedirCompType.DEFAULT:
+            comp_type = RedirCompType.NONE
 
-    if comp_type == RedirCompType.SHELL_CMD:
-        shell_cmd_complete_mock.assert_called_once()
-    elif comp_type == RedirCompType.PATH:
-        path_complete_mock.assert_called_once()
-    elif comp_type == RedirCompType.DEFAULT:
-        default_complete_mock.assert_called_once()
-    else:
-        shell_cmd_complete_mock.assert_not_called()
-        path_complete_mock.assert_not_called()
-        default_complete_mock.assert_not_called()
 
 def test_complete_set_value(cmd2_app):
     text = ''

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-mock
apt-get update apt-get install -y gcc
3.9
requirements/base.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.16
anyio==4.9.0
attrs==25.3.0
babel==2.17.0
backports.tarfile==1.2.0
cachetools==5.5.2
certifi==2025.1.31
cffi==1.17.1
chardet==5.2.0
charset-normalizer==3.4.1
click==8.1.8
-e git+https://github.com/python-cmd2/cmd2.git@729e152c525bc30d36f130f8dc8442aeb00d1de8#egg=cmd2
codecov==2.1.13
colorama==0.4.6
coverage==7.8.0
cryptography==44.0.2
distlib==0.3.9
doc8==1.1.2
docutils==0.21.2
exceptiongroup==1.2.2
filelock==3.18.0
flake8==7.2.0
h11==0.14.0
id==1.5.0
idna==3.10
imagesize==1.4.1
importlib_metadata==8.6.1
iniconfig==2.1.0
invoke==2.2.0
jaraco.classes==3.4.0
jaraco.context==6.0.1
jaraco.functools==4.1.0
jeepney==0.9.0
Jinja2==3.1.6
keyring==25.6.0
markdown-it-py==3.0.0
MarkupSafe==3.0.2
mccabe==0.7.0
mdurl==0.1.2
more-itertools==10.6.0
nh3==0.2.21
packaging==24.2
pbr==6.1.1
platformdirs==4.3.7
pluggy==1.5.0
pycodestyle==2.13.0
pycparser==2.22
pyflakes==3.3.1
Pygments==2.19.1
pyperclip==1.9.0
pyproject-api==1.9.0
pytest==8.3.5
pytest-cov==6.0.0
pytest-mock==3.14.0
readme_renderer==44.0
requests==2.32.3
requests-toolbelt==1.0.0
restructuredtext_lint==1.4.0
rfc3986==2.0.0
rich==14.0.0
SecretStorage==3.3.3
sniffio==1.3.1
snowballstemmer==2.2.0
Sphinx==7.4.7
sphinx-autobuild==2024.10.3
sphinx-rtd-theme==3.0.2
sphinxcontrib-applehelp==2.0.0
sphinxcontrib-devhelp==2.0.0
sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jquery==4.1
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
starlette==0.46.1
stevedore==5.4.1
tomli==2.2.1
tox==4.25.0
twine==6.1.0
typing_extensions==4.13.0
urllib3==2.3.0
uvicorn==0.34.0
virtualenv==20.29.3
watchfiles==1.0.4
wcwidth==0.2.13
websockets==15.0.1
zipp==3.21.0

name: cmd2
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - alabaster==0.7.16
      - anyio==4.9.0
      - attrs==25.3.0
      - babel==2.17.0
      - backports-tarfile==1.2.0
      - cachetools==5.5.2
      - certifi==2025.1.31
      - cffi==1.17.1
      - chardet==5.2.0
      - charset-normalizer==3.4.1
      - click==8.1.8
      - codecov==2.1.13
      - colorama==0.4.6
      - coverage==7.8.0
      - cryptography==44.0.2
      - distlib==0.3.9
      - doc8==1.1.2
      - docutils==0.21.2
      - exceptiongroup==1.2.2
      - filelock==3.18.0
      - flake8==7.2.0
      - h11==0.14.0
      - id==1.5.0
      - idna==3.10
      - imagesize==1.4.1
      - importlib-metadata==8.6.1
      - iniconfig==2.1.0
      - invoke==2.2.0
      - jaraco-classes==3.4.0
      - jaraco-context==6.0.1
      - jaraco-functools==4.1.0
      - jeepney==0.9.0
      - jinja2==3.1.6
      - keyring==25.6.0
      - markdown-it-py==3.0.0
      - markupsafe==3.0.2
      - mccabe==0.7.0
      - mdurl==0.1.2
      - more-itertools==10.6.0
      - nh3==0.2.21
      - packaging==24.2
      - pbr==6.1.1
      - platformdirs==4.3.7
      - pluggy==1.5.0
      - pycodestyle==2.13.0
      - pycparser==2.22
      - pyflakes==3.3.1
      - pygments==2.19.1
      - pyperclip==1.9.0
      - pyproject-api==1.9.0
      - pytest==8.3.5
      - pytest-cov==6.0.0
      - pytest-mock==3.14.0
      - readme-renderer==44.0
      - requests==2.32.3
      - requests-toolbelt==1.0.0
      - restructuredtext-lint==1.4.0
      - rfc3986==2.0.0
      - rich==14.0.0
      - secretstorage==3.3.3
      - sniffio==1.3.1
      - snowballstemmer==2.2.0
      - sphinx==7.4.7
      - sphinx-autobuild==2024.10.3
      - sphinx-rtd-theme==3.0.2
      - sphinxcontrib-applehelp==2.0.0
      - sphinxcontrib-devhelp==2.0.0
      - sphinxcontrib-htmlhelp==2.1.0
      - sphinxcontrib-jquery==4.1
      - sphinxcontrib-jsmath==1.0.1
      - sphinxcontrib-qthelp==2.0.0
      - sphinxcontrib-serializinghtml==2.0.0
      - starlette==0.46.1
      - stevedore==5.4.1
      - tomli==2.2.1
      - tox==4.25.0
      - twine==6.1.0
      - typing-extensions==4.13.0
      - urllib3==2.3.0
      - uvicorn==0.34.0
      - virtualenv==20.29.3
      - watchfiles==1.0.4
      - wcwidth==0.2.13
      - websockets==15.0.1
      - zipp==3.21.0
prefix: /opt/conda/envs/cmd2

tests/test_completion.py::test_redirect_complete[fake
tests/test_completion.py::test_cmd2_command_completion_single tests/test_completion.py::test_complete_command_single tests/test_completion.py::test_complete_empty_arg tests/test_completion.py::test_complete_bogus_command tests/test_completion.py::test_complete_exception tests/test_completion.py::test_complete_macro tests/test_completion.py::test_default_sort_key tests/test_completion.py::test_cmd2_command_completion_multiple tests/test_completion.py::test_cmd2_command_completion_nomatch tests/test_completion.py::test_cmd2_help_completion_single tests/test_completion.py::test_cmd2_help_completion_multiple tests/test_completion.py::test_cmd2_help_completion_nomatch tests/test_completion.py::test_shell_command_completion_shortcut tests/test_completion.py::test_shell_command_completion_doesnt_match_wildcards tests/test_completion.py::test_shell_command_completion_multiple tests/test_completion.py::test_shell_command_completion_nomatch tests/test_completion.py::test_shell_command_completion_doesnt_complete_when_just_shell tests/test_completion.py::test_shell_command_completion_does_path_completion_when_after_command tests/test_completion.py::test_shell_commmand_complete_in_path tests/test_completion.py::test_path_completion_single_end tests/test_completion.py::test_path_completion_multiple tests/test_completion.py::test_path_completion_nomatch tests/test_completion.py::test_default_to_shell_completion tests/test_completion.py::test_path_completion_no_text tests/test_completion.py::test_path_completion_no_path tests/test_completion.py::test_path_completion_cwd_is_root_dir tests/test_completion.py::test_path_completion_doesnt_match_wildcards tests/test_completion.py::test_path_completion_complete_user tests/test_completion.py::test_path_completion_user_path_expansion tests/test_completion.py::test_path_completion_directories_only tests/test_completion.py::test_basic_completion_single tests/test_completion.py::test_basic_completion_multiple tests/test_completion.py::test_basic_completion_nomatch tests/test_completion.py::test_delimiter_completion tests/test_completion.py::test_flag_based_completion_single tests/test_completion.py::test_flag_based_completion_multiple tests/test_completion.py::test_flag_based_completion_nomatch tests/test_completion.py::test_flag_based_default_completer tests/test_completion.py::test_flag_based_callable_completer tests/test_completion.py::test_index_based_completion_single tests/test_completion.py::test_index_based_completion_multiple tests/test_completion.py::test_index_based_completion_nomatch tests/test_completion.py::test_index_based_default_completer tests/test_completion.py::test_index_based_callable_completer tests/test_completion.py::test_tokens_for_completion_quoted tests/test_completion.py::test_tokens_for_completion_unclosed_quote tests/test_completion.py::test_tokens_for_completion_punctuation tests/test_completion.py::test_tokens_for_completion_quoted_punctuation tests/test_completion.py::test_add_opening_quote_basic_no_text tests/test_completion.py::test_add_opening_quote_basic_nothing_added tests/test_completion.py::test_add_opening_quote_basic_quote_added tests/test_completion.py::test_add_opening_quote_basic_single_quote_added tests/test_completion.py::test_add_opening_quote_basic_text_is_common_prefix tests/test_completion.py::test_add_opening_quote_delimited_no_text tests/test_completion.py::test_add_opening_quote_delimited_nothing_added tests/test_completion.py::test_add_opening_quote_delimited_quote_added tests/test_completion.py::test_add_opening_quote_delimited_text_is_common_prefix tests/test_completion.py::test_add_opening_quote_delimited_space_in_prefix tests/test_completion.py::test_no_completer tests/test_completion.py::test_quote_as_command tests/test_completion.py::test_complete_multiline_on_single_line tests/test_completion.py::test_complete_multiline_on_multiple_lines tests/test_completion.py::test_redirect_complete[fake-RedirCompType.DEFAULT] tests/test_completion.py::test_complete_set_value tests/test_completion.py::test_complete_set_value_invalid_settable tests/test_completion.py::test_cmd2_subcommand_completion_single_end tests/test_completion.py::test_cmd2_subcommand_completion_multiple tests/test_completion.py::test_cmd2_subcommand_completion_nomatch tests/test_completion.py::test_help_subcommand_completion_single tests/test_completion.py::test_help_subcommand_completion_multiple tests/test_completion.py::test_help_subcommand_completion_nomatch tests/test_completion.py::test_subcommand_tab_completion tests/test_completion.py::test_subcommand_tab_completion_with_no_completer tests/test_completion.py::test_subcommand_tab_completion_space_in_text tests/test_completion.py::test_subcmd_with_unknown_completion_single_end tests/test_completion.py::test_subcmd_with_unknown_completion_multiple tests/test_completion.py::test_subcmd_with_unknown_completion_nomatch tests/test_completion.py::test_help_subcommand_completion_single_scu tests/test_completion.py::test_help_subcommand_completion_multiple_scu tests/test_completion.py::test_help_subcommand_completion_with_flags_before_command tests/test_completion.py::test_complete_help_subcommands_with_blank_command tests/test_completion.py::test_help_subcommand_completion_nomatch_scu tests/test_completion.py::test_subcommand_tab_completion_scu tests/test_completion.py::test_subcommand_tab_completion_with_no_completer_scu tests/test_completion.py::test_subcommand_tab_completion_space_in_text_scu
cmd2/cmd2.py CHANGELOG.md
cmd2/cmd2.py CHANGELOG.md