`lineinfile` template generates `regexp: ''`, so remediation overwrites the last line of the target file

Cerrado
#15,034 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 2 días

@HSP18SCM23P ya está trabajando en esto.

Desde el 25/9/2026.

  • #15142 de @HSP18SCM23P — abierto

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
55/100
Tipo de issue
Error
Claridad
Bastante claro
Estado de actividad
Activo
Stack tecnológico
yaml
Área
devops, security

Línea de trabajo

Comienza con shared/templates/lineinfile/ansible.template y shared/macros/10-ansible.jinja, y después compara sus 14 puntos de llamada de ansible_lineinfile, especialmente sshd_lineinfile/ansible.template. Determina cómo deben proporcionar patrones anclados las siete reglas afectadas, incluido sssd_enable_certmap, y comprueba el Ansible generado junto con los backends de Bash y OVAL. Se considera terminado cuando la configuración existente se actualiza sin destruir otras líneas y las ejecuciones repetidas del playbook son idempotentes.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

Ansible triaged
Description of problem:

Every rule built on the lineinfile template emits an Ansible task with regexp: ''.
ansible.builtin.lineinfile uses regexp to find the line to replace, and an empty pattern
matches at position 0 of every line — so the module takes the last line of the file as its
match and overwrites it, instead of finding and updating the setting the rule manages.

On the first run this silently destroys a line of the target file. On every subsequent run it
appends another duplicate of the managed setting, without bound.

Root cause. shared/templates/lineinfile/ansible.template calls the macro without a regex
argument:

{{{ ansible_lineinfile(msg='', path=PATH, new_line=TEXT, create='yes', state='present',
                       insert_after='', insert_before='', rule_title=rule_title) -}}}

regex therefore falls back to its default of '' in shared/macros/10-ansible.jinja:31, and
line 39 emits it verbatim as regexp: '{{{ regex }}}'.

Of the 14 call sites of ansible_lineinfile in the repository, this is the only one that omits
regex — every other caller passes an anchored pattern (e.g.
regex='^\s*Include\s+\/usr\/etc\/ssh\/sshd_config\.d/\*\.conf' in
shared/templates/sshd_lineinfile/ansible.template).

Affected rules — all 7 rules using template: lineinfile on current master (df060c67):

Rule File whose last line is overwritten
accounts_password_pam_enforce_root pwquality.conf
accounts_password_pam_enforce_local pwquality.conf
accounts_password_pam_enforcing pwquality.conf
accounts_password_pam_pwhistory_enforce_for_root /etc/security/pwhistory.conf
set_firewalld_default_zone /etc/firewalld/firewalld.conf
sssd_enable_certmap /etc/sssd/sssd.conf
verify_use_mappers /etc/pam_pkcs11/pam_pkcs11.conf
SCAP Security Guide Version:

Reproduced against scap-security-guide 0.1.81 (Rocky Linux 9.8 appstream package).
Root cause confirmed still present on master at df060c67.
ansible-core 2.21.3.

Operating System Version:

Rocky Linux 9.8 (Blue Onyx), aarch64, kernel 5.14.0-687.10.1.el9_8.0.1.aarch64.
Fresh install, no prior remediation.

Steps to Reproduce:
  1. Generate the Ansible remediation for profile cis_server_l1
    (/usr/share/scap-security-guide/ansible/rl9-playbook-cis_server_l1.yml).
  2. Record the stock contents of /etc/security/pwquality.conf and
    /etc/security/pwhistory.conf — in particular their final lines.
  3. Run the playbook against a fresh host.
  4. Run the identical playbook against the same host twice more, and diff both files after each run.
Actual Results:

The generated task for accounts_password_pam_enforce_root:

- name: Ensure PAM Enforces Password Requirements - Enforce for root User
  ansible.builtin.lineinfile:
    path: /etc/security/pwquality.conf
    create: true
    regexp: ''            # ← matches at position 0 of every line
    line: enforce_for_root
    state: present

After three consecutive applies:

stock after 3 applies
/etc/security/pwquality.conf lines 79 82
/etc/security/pwhistory.conf lines 21 24
occurrences of enforce_for_root in each 0 3
stock final line of pwquality.conf # local_users_only destroyed on run 1
stock final line of pwhistory.conf # file = /etc/security/opasswd destroyed on run 1

Run 1 overwrites the file's last line. Runs 2 and 3 each append another enforce_for_root,
because the pattern still fails to find the setting it just wrote. Applied on a schedule the
duplicates grow linearly — a weekly run for a year leaves 52 copies.

Expected Results:

The task finds an existing enforce_for_root setting and updates it in place, or appends it if
absent. No pre-existing line is modified, and a second run reports ok rather than changed.

Additional Information/Debugging Steps:

Why this is easy to miss. PAM reads the last occurrence of a setting, so the end state is
compliant. The compliance score does not move (97.4 on all three passes here), the OVAL check
passes, and no before/after scan delta reports anything. It is only visible by running the
remediation twice and reading the file.

On a pristine box the destroyed line is a comment. On a system an administrator has edited — the
usual state of a real host — the last line of pwquality.conf is as likely to be a setting they
added.

Two further consequences worth noting:

  • Three of the seven target the same file (pwquality.conf). In a profile selecting more than
    one, each task overwrites whatever the previous one appended, so they destroy each other's work
    rather than only the stock content. I could not find a user-facing profile in this state — the
    only profiles selecting two of the three are the internal hidden: true default profiles for
    Fedora, Ubuntu 22.04 and Ubuntu 24.04, and I did not trace rule selection through control files.
    So this is a latent hazard rather than a reproduced one.
  • sssd_enable_certmap and set_firewalld_default_zone write to service configuration, where
    losing the final line is a plausible outage rather than a lost comment.

Suggested fix. Give the template an anchored pattern so the module finds the setting it
manages — roughly:

{{{ ansible_lineinfile(msg='', path=PATH, new_line=TEXT, regex=REGEX,
                       create='yes', state='present', ...) -}}}

with a per-rule regex var defaulting to an anchored match on the managed key.
sssd_enable_certmap already passes escape_text: false and a regex-shaped text, so it likely
needs handling of its own.

I have not opened a PR because the right default (derive the pattern from text, versus require an
explicit regex var on each of the 7 rules) is a judgement call for maintainers, and any fix
should be checked against the Bash and OVAL backends too. Happy to submit one if you tell me which
shape you would prefer.

Lenguaje dominante
Shell
Estrellas
2.8k
Forks
847
Merge medio
3 d 5 h
PR fusionados (30 d)
86

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de ComplianceAsCode/content

Todos los issues de ComplianceAsCode/content

Issues similares

Más issues de Shell/Bash

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.